Skip to content

feat(docs): bootstrap RULE blocks in go-logging-guide.md (+6 rules)#35

Merged
bborbe merged 4 commits into
masterfrom
feat/bootstrap-logging-rules
Jun 3, 2026
Merged

feat(docs): bootstrap RULE blocks in go-logging-guide.md (+6 rules)#35
bborbe merged 4 commits into
masterfrom
feat/bootstrap-logging-rules

Conversation

@bborbe

@bborbe bborbe commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Summary

Rule count: 124 → 130. Bootstraps the previously 0-rule `docs/go-logging-guide.md` with 6 RULE blocks following the rule-block-schema.

# Rule Level Owner
1 `go-logging/no-mixing-slog-and-glog` MUST go-quality-assistant
2 `go-logging/no-log-and-return-error` MUST go-quality-assistant
3 `go-logging/external-call-logs-response` MUST go-quality-assistant
4 `go-logging/no-sensitive-data-in-logs` MUST go-security-specialist
5 `go-logging/lowercase-log-messages` SHOULD go-quality-assistant
6 `go-logging/no-tight-loop-without-sampler` SHOULD go-quality-assistant

Why no ast-grep YAMLs

All 6 enforcements are judgment-tier with ast-grep partial hints. The MUSTs need cross-context reasoning:

#5 + #6 are tractable mechanically (regex on first string-literal / for-statement scan) but the false-positive rate without semantic filtering would be high — leaving them judgment-tier with hints lets the dispatcher's agent layer adjudicate.

Preserves existing content

Operator-content sections (slog/glog usage, sampling, runtime log level, related rules) preserved verbatim. This is a bootstrap (add RULE blocks), not a rewrite.

Test plan

  • `make precommit` clean (130 rules, no drift)
  • `make check-index` clean (walker picks up all 6 new rules with Owner / Applies-when / Enforcement fields)
  • Each rule has Why paragraph and Bad/Good examples per schema
  • Bot review

Rule count: 124 -> 130.

Added 6 RULE blocks to a previously 0-rule doc:
- go-logging/no-mixing-slog-and-glog (MUST)
- go-logging/no-log-and-return-error (MUST)
- go-logging/external-call-logs-response (MUST)
- go-logging/no-sensitive-data-in-logs (MUST)
- go-logging/lowercase-log-messages (SHOULD)
- go-logging/no-tight-loop-without-sampler (SHOULD)

All carry judgment-tier enforcement with ast-grep partial hints
where applicable; the 4 MUSTs are semantic (project-wide logger
choice, inner-vs-boundary intent, boundary-call recognition,
credential-shaped variable detection) and need agent adjudication
to avoid false-positive fatigue.

Existing operator-content (slog/glog usage, sampling, runtime log
level, related rules) preserved verbatim below the Rules section
— this is a doc bootstrap, not a rewrite.

make precommit clean: 130 rules, 20 mechanical YAMLs, no drift.

Closes part of 'All 67 docs carry rule-block structure for their
MUST/SHOULD content' success criterion. 0-rule docs remaining: 15
(was 16).

@ben-s-pull-request-reviewer ben-s-pull-request-reviewer 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.

Based on my analysis of the diff, here is my review:

PR Review Summary

Scope: Documentation-only change (6 new RULE blocks + index entries)

Findings

Should Fix (Important):

  1. Lost guidance - "V(2) with nothing to report": The old inline Rules section had 8 bullets, but only 6 formal RULE blocks were created. The specific guidance "V(2) with nothing to report — skip the log line, or use sampling" was removed without a corresponding formal RULE. The closest rule is no-tight-loop-without-sampler, but that covers tight loops specifically, not the general "skip logging when there's nothing useful to report at V(2)" guidance.

  2. index.json applies_when field truncation: The applies_when field for go-logging/external-call-logs-response in index.json contains embedded backtick-wrapped code (exec\) that may cause JSON parsing issues depending on the validation tooling.

Correctly Addressed

  • Security rule (no-sensitive-data-in-logs) properly distinguishes credential vs credential-shaped name (e.g., publicKey)
  • All 6 index entries have consistent structure with correct anchor, doc_path, owner, and level fields
  • The "External Calls — Always Log" prose was properly converted to the external-call-logs-response RULE block with retained specificity
  • All enforcement descriptions accurately describe the judgment-tier nature with ast-grep partial patterns

No Code Changes

This is a docs-only PR. No Go code was modified, so no make precommit or ast-grep analysis is applicable.


{
  "verdict": "request-changes",
  "summary": "The PR adds 6 well-structured RULE blocks to go-logging-guide.md with corresponding index.json entries, correctly converting prose rules into formal enforcement blocks. However, the 'V(2) with nothing to report' bullet from the old inline Rules section has no corresponding RULE block — that guidance was lost in the conversion. Additionally, the index.json applies_when field for external-call-logs-response contains embedded backticks that may cause JSON parsing issues.",
  "comments": [
    {
      "file": "docs/go-logging-guide.md",
      "line": 1,
      "severity": "major",
      "message": "Should Fix: The old inline 'Rules' section had 8 bullets but only 6 formal RULE blocks were created. The guidance 'V(2) with nothing to report — skip the log line, or use sampling' was removed without a corresponding formal RULE block. Either add a RULE block for this guidance or explicitly note it as intentionally out of scope."
    },
    {
      "file": "rules/index.json",
      "line": 614,
      "severity": "minor",
      "message": "Nice to Have: The applies_when field for go-logging/external-call-logs-response contains backtick-wrapped code (`exec`) inside a JSON string. While not a parse error, this pattern may cause issues with some JSON validation tools that treat backticks as special characters."
    }
  ],
  "concerns_addressed": [
    "security: go-logging/no-sensitive-data-in-logs correctly distinguishes credential from credential-shaped names (e.g., publicKey) — VERIFIED",
    "correctness: The 6 new RULE blocks cover the main bullets but 'V(2) with nothing to report' guidance was lost — GAP IDENTIFIED",
    "correctness: index.json entries have correct anchor, doc_path, applies_when, enforcement, level, and owner fields — VERIFIED",
    "correctness: External Calls prose properly converted to go-logging/external-call-logs-response RULE block — VERIFIED",
    "tests: Cannot verify 'make check-index' from diff alone — no code changes in this PR"
  ]
}

Bot flagged that 'V(2) with nothing to report — skip the log line,
or use sampling' bullet from the original go-logging-guide.md
Rules section was dropped during the bootstrap conversion. Added
as the 7th formal RULE block.

Owner: go-quality-assistant. SHOULD-level (not MUST — it's a
production-tuning recommendation, not a correctness issue).
Enforcement is judgment-tier with ast-grep partial hint:
'call_expression matching glog.V(2).Info*(...) inside for_statement
body without a preceding guard'. Bad/Good examples show the typical
scan-cycle-zero-changed pattern.

Bot MINOR re backticks in JSON applies_when string: not addressing
— JSON spec doesn't treat backticks as special, no real parser
issue. Multiple existing rules in index.json use backtick-wrapped
code in applies_when text already; precedent stands.

Rule count: 130 -> 131. make precommit clean, no drift.

@ben-s-pull-request-reviewer ben-s-pull-request-reviewer 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.

Based on my review of the diff (docs-only: docs/go-logging-guide.md + rules/index.json), I found 2 important issues and no critical ones.

Must Fix (Important)

  1. go-logging/external-call-logs-response — Good example missing latency (docs/go-logging-guide.md:104-105)

    The rule's Applies-when and Why both state "minimum payload: method + path/op + status code + latency", but the Good example only logs status and body_len — no latency:

    glog.Infof("http POST %s status=%d body_len=%d", path, status, len(body))

    Fix: add elapsed or time.Since(start) to the log line, or update the rule text to remove latency from the minimum payload.

  2. go-logging/external-call-logs-response — Narrow examples vs broad scope (docs/go-logging-guide.md:83-111)

    The Applies-when covers HTTP, gRPC, DB, message-bus, and subprocess — but the only example is HTTP. The deleted prose section had distinct gRPC and DB query examples (with latency). The rule is correct, but the examples underrepresent its scope. Consider adding at least one gRPC or DB example to match the breadth described in Applies-when.

Nice to Have (Optional)

  1. go-logging/external-call-logs-response — Missing V-level guidance (docs/go-logging-guide.md:83-111)

    The old "External Calls" prose included verbosity selection: V0 for low-frequency boundary calls, sampled V(2) for high-frequency. The new rule doesn't capture this operational nuance. Consider adding it to the Why or Applies-when.

Verified Correct ✓

  • All 6 rules/index.json entries are well-formed (id, anchor, applies_when, enforcement, level, owner, doc_path all present)
  • All Owner assignments are correct: 5× go-quality-assistant, 1× go-security-specialist
  • All Enforcement fields correctly describe "judgment + ast-grep partial" or "judgment" semantics
  • All Why paragraphs are accurate and non-circular
  • Related Rules section links: go-cli/slog-not-glog-in-new-projects ✓, go-glog/use-v-for-debug-not-info ✓, go-k8s-binary/secret-fields-need-display-length
  • All 6 Bad/Good examples are syntactically valid Go and illustrate the rule correctly
  • JSON syntax of index.json entries is structurally valid (matching adjacent entries)

{
  "verdict": "request-changes",
  "summary": "Six new logging RULE blocks are well-structured and mostly correct, but the external-call-logs-response rule has an inconsistency between its stated minimum payload (includes latency) and its Good example (omits latency), plus examples that are narrow compared to the broad scope described.",
  "comments": [
    {
      "file": "docs/go-logging-guide.md",
      "line": 104,
      "severity": "major",
      "message": "go-logging/external-call-logs-response: Good example logs status and body_len but no latency, contradicting the rule's stated minimum payload (\"method + path/op + status code + latency\"). Add elapsed time to the log line, e.g. via time.Since(start), or update Applies-when/Why to remove latency from the minimum."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 102,
      "severity": "nit",
      "message": "go-logging/external-call-logs-response: Applies-when covers HTTP, gRPC, DB, message-bus, and subprocess, but only the HTTP example is shown. The deleted prose had gRPC and DB examples — consider adding one to match the stated scope."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 88,
      "severity": "nit",
      "message": "go-logging/external-call-logs-response: The old \"External Calls\" prose included V-level guidance (V0 for low-frequency calls, sampled V(2) for high-frequency). This operational nuance is missing from the new rule's Why — consider adding it."
    }
  ],
  "concerns_addressed": [
    "correctness: go-logging/no-sensitive-data-in-logs — Why paragraph correctly captures credential-shaped field names vs actual credentials, Bad/Good examples are accurate",
    "correctness: go-logging/no-mixing-slog-and-glog — Bad/Good examples cover module-level logger consistency correctly",
    "correctness: go-logging/no-log-and-return-error — examples correctly distinguish diagnostic logging from accidental double-log",
    "correctness: go-logging/external-call-logs-response — PARTIAL: boundary/client call patterns described in Applies-when but examples narrow (HTTP only) and latency missing from Good example",
    "correctness: rules/index.json — all 6 entries correctly reference Owner, Applies-when, Enforcement fields per schema"
  ]
}

@ben-s-pull-request-reviewer ben-s-pull-request-reviewer Bot dismissed stale reviews from themself June 2, 2026 22:40

superseded by new automated review

@ben-s-pull-request-reviewer ben-s-pull-request-reviewer 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.


PR Review Report: feat/bootstrap-logging-rulesmaster

Changes

  • docs/go-logging-guide.md — 6 new ### RULE blocks (+7th: skip-empty-v2-heartbeats was added in a prior fix commit), removed the old prose "External Calls" section
  • rules/index.json — 7 new rule entries

Precommit Checks

  • make precommit could not be executed in this environment (worktree sandbox blocked cd + hook invocation), but JSON validity of rules/index.json was confirmed via direct read by the go-quality-assistant agent. All 7 new rule IDs are consistent between doc anchors and index entries. LICENSE file is present.

Automated Findings

None — this is a docs-only change adding judgment-tier rule definitions. No Go source files were modified, so no ast-grep mechanical findings apply.


Consolidated Report

Must Fix (Critical)

# Rule Issue
1 go-logging/no-log-and-return-error Good example references undefined id — the boundary handler's Good example calls h.svc.FetchUser(r.Context(), id) but id is never declared in the snippet. Reader cannot determine whether it comes from a path param, query string, or prior scope. Add id := chi.URLParam(r, "id") (or equivalent) above the call.
2 go-logging/no-tight-loop-without-sampler Good example uses h.logSampler with no wiring context — the snippet drops h.logSampler mid-pattern with no indication of where it is constructed or injected. The Sampling section of the same doc shows the constructor signature but the snippet doesn't reference it. Add // sampler wired via handler constructor or a (*Handler) WithSampler(log.Sampler) inline note.
3 go-logging/no-sensitive-data-in-logs Regex .*Key is over-broad — matches any identifier containing key as a substring: partitionKey, sortKey, lookupKey, keyValue — none of which are secrets. Will produce severe false-positive fatigue in codebases using k8s or map keyed structs. Replace .*Key with a bounded alternation: (private|public|api|encryption|signing)?Key\b or a positive list of credential-shaped identifiers.
4 go-logging/no-sensitive-data-in-logs Regex secret catches k8s secret references, not secret valuessecretName, secretRef, secretNamespace are metadata about a K8s Secret object; logging them is safe. The current pattern flags them all. Fix: use word boundaries (\bsecret(s)?\b) or scope to credential-named variables (secretKey|clientSecret|secretValue).
5 go-logging/no-sensitive-data-in-logs (?i) is not group-scoped — the alternation (?i)password|token|... in most regex engines applies case-insensitivity only to the first alternative (password), silently missing Token, Secret, KEY, Authorization. Fix: (?i)(password|token|secret|\w*Key|PEM|JWT|credential|authorization).

Should Fix (Important)

# Rule Issue
6 go-logging/no-mixing-slog-and-glog Overlaps with go-cli/slog-not-glog-in-new-projects without declaring the boundarygo-cli fires for a new binary picking glog; go-logging fires for dual-logger coexistence in the same binary. Neither doc states this distinction. Add a clarifying sentence to the applies_when or Why section.
7 go-logging/no-log-and-return-error No cross-link to go-errors/ rules — the boundary-logging pattern depends on callers properly wrapping errors (governed by go-errors/inner-closure-no-double-wrap or go-errors/no-bare-return-err). Add one of those to the Related Rules block.
8 go-logging/external-call-logs-response Good example logs AND returns the error, contradicting no-log-and-return-error — the glog.Warningf(...) + return err combo in the success-path snippet is the exact anti-pattern this PR introduces in the sibling rule. Either add a note that this is the boundary exception (which is correct) or restructure the example to not show both on the error path.
9 go-logging/no-sensitive-data-in-logs applies_when omits common credential carriers — missing: Authorization headers, DB connection strings/DSNs, private keys (privateKey, privKey), API keys (apiKey), session IDs, certificates, passphrases. The regex has authorization but the prose description does not name it.
10 go-logging/no-sensitive-data-in-logs All examples use glog; slog examples are absent — the rule and enforcement text cover slog.Info / slog.Error, but neither BAD nor GOOD snippet shows slog key-value pair style. New projects recommended slog in the doc's opening line — these readers have no slog example to follow.
11 go-logging/no-sensitive-data-in-logs BAD example omits the most common credential-leak vector: logging HTTP request/response structsglog.Infof("request: %+v", r) where r is *http.Request dumps the Authorization header. This is the #1 real-world leak pattern and is absent from the examples.

Nice to Have (Optional)

# Rule Issue
12 go-logging/no-tight-loop-without-sampler ~100 items threshold is unquantified — no justification for why 100 triggers the rule. Consider "log volume exceeds operator-scannable thresholds at expected load" or tie to ops/sec.
13 go-logging/skip-empty-v2-heartbeats Good/Bad examples use time.Sleep not context-aware shutdown — the for { ... time.Sleep(interval) } pattern ignores ctx.Done(). A one-line // use select+ctx.Done() for graceful shutdown comment would prevent copy-paste into production loops.
14 go-logging/external-call-logs-response No cross-link to no-tight-loop-without-sampler — the Why mentions sampled V(2) for hot paths but the Related Rules block doesn't link to the sibling sampling rule.
15 go-logging/no-sensitive-data-in-logs Related Rules section missing cross-link to go-k8s-binary/secret-fields-need-display-length — the Why paragraph references it inline, but the bottom-of-doc Related Rules list omits it.

Next Steps

  • Fix Must Fix items 1–5 before merge (items 3–5 are single-line regex fixes).
  • Consider addressing Should Fix items 6–11 in the same PR to prevent rule conflicts and missing coverage.
  • Run make build-index && make precommit after editing to validate links and JSON.

{
  "verdict": "request-changes",
  "summary": "PR adds 7 well-structured judgment-tier logging rules to go-logging-guide.md and rules/index.json, but 5 critical correctness issues were found: an undefined variable in a Good example, a missing Sampler wiring context, and 3 regex bugs in the no-sensitive-data-in-logs enforcement pattern that will cause false positives (over-broad .*Key, ungrouped (?i), k8s secret-ref matching). 6 important secondary issues include rule-boundary ambiguity with go-cli/slog-not-glog-in-new-projects, a Good example that contradicts the sibling no-log-and-return-error rule, missing slog examples, and missing credential categories in the applies_when description.",
  "comments": [
    {
      "file": "docs/go-logging-guide.md",
      "line": 73,
      "severity": "critical",
      "message": "go-logging/no-log-and-return-error: Good example references undefined `id` variable in `h.svc.FetchUser(r.Context(), id)`. Add `id := chi.URLParam(r, \"id\")` (or equivalent) above the call so the snippet is self-contained."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 181,
      "severity": "critical",
      "message": "go-logging/no-tight-loop-without-sampler: Good example uses `h.logSampler` with no constructor context or wiring explanation. Add `// sampler wired via handler constructor` or reference the Sampling section so the reader can reproduce it."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 125,
      "severity": "critical",
      "message": "go-logging/no-sensitive-data-in-logs: ast-grep regex `.*Key` matches any identifier containing 'key' (partitionKey, sortKey, lookupKey) — not just credential keys. Replace with bounded alternation: `(private|public|api|encryption|signing)?Key\\b` or a positive list of credential-shaped identifiers."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 125,
      "severity": "critical",
      "message": "go-logging/no-sensitive-data-in-logs: ast-grep regex `secret` matches k8s secret *references* (secretName, secretRef, secretNamespace) which are safe to log — not secret values. Use word boundaries (`\\bsecret(s)?\\b`) or scope to credential-named variables only."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 125,
      "severity": "critical",
      "message": "go-logging/no-sensitive-data-in-logs: ast-grep regex `(?i)` is ungrouped — in most regex engines it applies case-insensitivity only to the first alternative 'password', silently missing Token, Secret, KEY, Authorization. Fix: `(?i)(password|token|secret|\\w*Key|PEM|JWT|credential|authorization)`."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 10,
      "severity": "major",
      "message": "go-logging/no-mixing-slog-and-glog: overlaps with go-cli/slog-not-glog-in-new-projects without declaring the rule boundary. go-cli fires for 'new binary picks glog'; go-logging fires for 'same binary uses both'. Add a clarifying sentence distinguishing the two triggers."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 40,
      "severity": "major",
      "message": "go-logging/no-log-and-return-error: no cross-link to go-errors/ rules (e.g., inner-closure-no-double-wrap or no-bare-return-err). The boundary-logging pattern depends on callers properly wrapping errors — the Related Rules block should name the companion error-handling rule."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 103,
      "severity": "major",
      "message": "go-logging/external-call-logs-response: Good example does `glog.Warningf(..., err) + return err` — the exact go-logging/no-log-and-return-error anti-pattern introduced in this same PR. Either note this is the boundary exception or restructure the example to avoid contradicting the sibling rule."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 113,
      "severity": "major",
      "message": "go-logging/no-sensitive-data-in-logs: applies_when omits common credential carriers: Authorization headers, DB connection strings/DSNs, privateKey/privKey, apiKey, session IDs, certificates, passphrases. The prose and regex are inconsistent."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 127,
      "severity": "major",
      "message": "go-logging/no-sensitive-data-in-logs: all GOOD examples use glog; slog key-value pair examples are absent despite the rule explicitly covering slog.Info/slog.Error. New projects recommended slog in the doc's opening — those readers have no slog example to follow."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 127,
      "severity": "major",
      "message": "go-logging/no-sensitive-data-in-logs: BAD example omits the most common credential-leak vector: logging an HTTP request/response struct (`glog.Infof(\"request: %+v\", r)` dumps the Authorization header). Add this as the primary BAD example."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 162,
      "severity": "nit",
      "message": "go-logging/no-tight-loop-without-sampler: the '~100 items' threshold is unquantified with no justification. Consider 'log volume exceeding operator-scannable thresholds at expected load' or tie to ops/sec."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 231,
      "severity": "nit",
      "message": "go-logging/skip-empty-v2-heartbeats: Good and Bad examples use time.Sleep without context-aware shutdown. A one-line `// use select+ctx.Done() for graceful shutdown` comment would prevent the pattern from being copy-pasted into production infinite loops."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 88,
      "severity": "nit",
      "message": "go-logging/external-call-logs-response: the Why mentions sampled V(2) for hot paths but Related Rules doesn't cross-link to no-tight-loop-without-sampler. The two rules are structurally related — add the link."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 310,
      "severity": "nit",
      "message": "go-logging/no-sensitive-data-in-logs: Related Rules section omits go-k8s-binary/secret-fields-need-display-length even though the Why paragraph references it inline. Add it to the Related Rules block at the bottom of the doc."
    }
  ],
  "concerns_addressed": [
    "tests: 6 new rules documented with ast-grep partial patterns — patterns validated against doc consistency by go-quality-assistant and go-security-specialist; found 3 regex correctness bugs in no-sensitive-data-in-logs that would cause false positives/negatives in real code review, plus 2 snippet correctness issues and 6 rule-boundary/coverage issues"
  ]
}

…de.md

5 CRITICAL fixed:
- no-log-and-return-error Good example: added 'id := chi.URLParam(r, "id")'
  so the snippet is self-contained
- no-tight-loop-without-sampler Good example: added comment pointing
  reader to the Log Sampling section for h.logSampler wiring context
- no-sensitive-data-in-logs Enforcement regex: rewrote with word
  boundaries and explicit credential-shaped key list. Was:
    (?i)password|token|secret|.*Key|PEM|JWT|credential|authorization
  Now:
    (?i)(password|passphrase|token|credential|authorization|jwt|pem|dsn|connection[_ ]?string)\b|(private|signing|encryption|api)Key\b
  - Drops bare '.*Key' (was matching partitionKey/sortKey/lookupKey)
  - Adds \b on 'secret' (was matching secretName/secretRef/secretNamespace)
  - Groups (?i) so case-insensitivity covers the whole alternation
  - Explicit credential-shaped key list (private/signing/encryption/api)

6 MAJOR fixed:
- no-mixing-slog-and-glog: added rule-boundary paragraph vs
  go-cli/slog-not-glog-in-new-projects (new-binary check vs
  same-binary-mixes-both check)
- no-log-and-return-error: cross-link to go-errors/no-bare-return-err
  in Related rules note
- external-call-logs-response: added 'Carve-out from
  no-log-and-return-error' paragraph; restructured Good example to
  emit ONE audit line per call (success branch OR failure branch,
  never both); cross-link to no-tight-loop-without-sampler for hot
  paths
- no-sensitive-data-in-logs applies_when: expanded to name
  Authorization headers, DSNs, OAuth client secrets, X.509 certs,
  whole-request/response struct dumps via %+v
- no-sensitive-data-in-logs Good examples: added slog key-value pair
  examples (rule covered slog but examples were glog-only)
- no-sensitive-data-in-logs Bad examples: added
  'glog.Infof("request: %+v", r)' as PRIMARY bad example (most
  common Authorization-header leak vector per bot)

4 NITs fixed:
- no-tight-loop-without-sampler applies_when: replaced '~100 items'
  threshold with 'iteration count unbounded at compile time' +
  judgment guidance tied to ops/sec
- skip-empty-v2-heartbeats Bad/Good: added 'select+ctx.Done()' for
  graceful shutdown; cross-link to go-context-cancellation-in-loops
- external-call-logs-response: added Related cross-link to
  no-tight-loop-without-sampler for sampled audit lines in hot paths
- Related Rules section: added
  go-k8s-binary/secret-fields-need-display-length,
  go-errors/no-bare-return-err, go-context-cancellation-in-loops

NIT not addressed: bot raised concern about backticks in
applies_when string causing JSON validation tool issues. JSON spec
doesn't treat backticks as special — multiple existing rules use
backtick-wrapped code in applies_when. Precedent stands.

Rule count unchanged: 131. make precommit clean.
@ben-s-pull-request-reviewer ben-s-pull-request-reviewer Bot dismissed their stale review June 2, 2026 22:59

superseded by new automated review

@ben-s-pull-request-reviewer ben-s-pull-request-reviewer 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.

{
  "verdict": "request-changes",
  "summary": "Documentation quality is high and the rule structure is sound, but two Important issues need resolution before merge: (1) the `go-logging/no-sensitive-data-in-logs` RULE block incorrectly lists `go-quality-assistant` as owner while `rules/index.json` correctly lists `go-security-specialist` — an inconsistency that will break dispatcher routing; (2) the `cookie` credential type was present in the pre-expansion `Applies when` text but is absent from both the expanded narrative and the enforcement regex, creating a real coverage gap for session/auth cookie leaks. Several Optional improvements are also noted for completeness.",
  "comments": [
    {
      "file": "docs/go-logging-guide.md",
      "line": 127,
      "severity": "major",
      "message": "[Should Fix] `no-sensitive-data-in-logs` RULE block has `**Owner**: go-quality-assistant` but `rules/index.json` entry at line 657 correctly assigns it to `go-security-specialist`. This owner mismatch will cause the dispatcher to route this rule to the wrong agent. Change line 127 to `**Owner**: go-security-specialist`."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 128,
      "severity": "major",
      "message": "[Should Fix] `cookie` (session/auth/tracking) was explicitly listed in the pre-expansion `Applies when` text but is absent from the expanded version. Cookies are a distinct credential-leak vector from `Authorization` headers and are not subsumed by them. The enforcement regex on line 129 also lacks `cookie`. Add `cookie (session / auth / tracking, including Set-Cookie header value)` to the Applies_when list and `cookie|set-cookie` to the regex alternation."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 129,
      "severity": "nit",
      "message": "[Nice to Have] The enforcement regex omits `\bsecret\b` as a standalone keyword, even though `secret` is listed in `Applies when`. Compound names like `signingSecret`, `clientSecret`, `webhookSecret` may not be caught. Consider adding `\bsecret\b` to the broad alternation. Note: `\b` boundary prevents matching `secretName`/`secretRef` (already handled by k8s exclusion), but a negative lookbehind `(?<![a-zA-Z])` could additionally guard against `secretName` if needed."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 111,
      "severity": "nit",
      "message": "[Nice to Have] `external-call-logs-response` Good example does not include latency, despite the rule's `Why` paragraph stating 'method + path/op + status code + latency' is the minimum payload. A reader copying the example would omit elapsed time. Consider adding `start := time.Now()` + `elapsed_ms=%d` to both branches."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 113,
      "severity": "nit",
      "message": "[Nice to Have] The removed `External Calls — Always Log` prose section contained a concrete `db.QueryContext` + `time.Since(start)` example that established the latency-instrumentation convention. The new rule's Good example covers HTTP only. Consider adding a one-line DB/gRPC variant or a 'DB / gRPC / subprocess follow the same shape' note to prevent information loss."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 156,
      "severity": "nit",
      "message": "[Nice to Have] The slog `connecting` Good example logs `dsn_len` but omits the database host/name — an operator seeing `dsn_len=87 driver=postgres` cannot identify which database logged the line. Consider adding a non-sensitive identifier (host, db name) alongside the length for operational utility."
    },
    {
      "file": "docs/go-logging-guide.md",
      "line": 129,
      "severity": "nit",
      "message": "[Nice to Have] The Enforcement field states 'Whole-struct dumps via `%+v` / `%#v` of any request / response / config struct also flag' but the provided regex is identifier-based and cannot mechanically correlate a `%+v` verb with the argument's struct type. Consider clarifying: 'Whole-struct dumps via `%+v` / `%#v` require judgment-tier review — ast-grep can flag the format verb but cannot determine whether the struct contains credential fields.'"
    }
  ],
  "concerns_addressed": [
    "docs: PR title '+6 rules' vs 7 actual RULE blocks — adequately explained by git commit history (7th added in follow-up commit 1bba0f4). No action needed.",
    "docs: 'External Calls — Always Log' prose section removed — noted as information loss (DB/gRPC examples gone). Not blocking but Nice to Have to add back a DB/gRPC variant.",
    "docs: 7 entries in index.json confirmed (all 7 go-logging rules present at lines 615-673). No mismatch.",
    "correctness: skip-empty-v2-heartbeats rule confirmed in both doc (lines 198-240) and index.json (lines 669-673). Intentionally included.",
    "security: no-sensitive-data-in-logs expansion in 9a5bb2b is appropriate (covers Authorization-header dump, structured slog leaks, DSN) — however cookie coverage was regressed and owner is wrong (both flagged above)."
  ]
}

MAJOR resolved:
- cookie credential type re-added to no-sensitive-data-in-logs
  applies_when list (was 'full session cookie' in the original
  draft; got dropped during the round-2 regex/applies_when
  expansion). Enforcement regex now includes 'cookie|set[_-]?cookie'.
- compound *Secret (clientSecret, webhookSecret, signingSecret)
  added to enforcement regex via '\b(private|signing|encryption|
  api|client|webhook)(Key|Secret)\b' alternation.

Bot MAJOR #1 not addressed (owner mismatch claim): bot reported
'docs line 127 says Owner: go-quality-assistant'. Verified — doc
line 127 is 'Owner: go-security-specialist' (correct), matching
index.json. The bot's claim is a hallucination on this round.

NITs addressed:
- external-call-logs-response Good example: added 'start := time.Now()'
  + elapsed_ms to both branches per rule's Why paragraph stating
  latency is part of the minimum payload
- Added DB / gRPC / subprocess Good-example variants showing the
  same one-log-line-per-call shape (replaces the prose 'External
  Calls' section that was lost during bootstrap)
- slog 'connecting' Good example now logs host + db name in
  addition to dsn_len (operator can identify which database)
- Enforcement field clarification: whole-struct %+v / %#v dumps
  are judgment-tier (ast-grep cannot mechanically correlate the
  format verb with the argument's struct type — agent reads
  fields)

NIT not addressed: bot's 'add bare secret to regex' — already
covered by the new (Key|Secret) compound alternation.

Rule count unchanged: 131. make precommit clean.
@ben-s-pull-request-reviewer ben-s-pull-request-reviewer Bot dismissed their stale review June 3, 2026 05:57

superseded by new automated review

@ben-s-pull-request-reviewer ben-s-pull-request-reviewer 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.

Based on my thorough review of PR #35, here's my analysis:

Review Summary

This PR bootstraps 6 RULE blocks in docs/go-logging-guide.md and registers them in rules/index.json. It also removes the "External Calls — Always Log" prose section, replacing it with the new rule-based cross-references.

Anchor Verification — All 6 Pass ✓

All anchors in rules/index.json match the markdown headings exactly:

  • go-logging/no-mixing-slog-and-glog
  • go-logging/no-log-and-return-error
  • go-logging/external-call-logs-response
  • go-logging/no-sensitive-data-in-logs
  • go-logging/lowercase-log-messages
  • go-logging/no-tight-loop-without-sampler
  • go-logging/skip-empty-v2-heartbeats

Concerns Addressed:

  1. no-sensitive-data-in-logs regex: The \bkey\b pattern correctly does NOT match key inside partitionKey/sortKey/lookupKey — there's no word boundary between i and k. The exemptions work correctly.

  2. external-call-logs-response carve-out: The rule says "emit exactly one audit line per boundary call — success path OR failure path, never both." This is intentionally flexible — failure-only (shown in Bad example) or success-only are both valid. The examples are consistent with the rule.

  3. no-log-and-return-error partial ast-grep: The pattern is intentionally narrow ("partial pattern") as documented — judgment tier supplements it. Scope is by design.

  4. Removed prose replaced by rules: The old "External Calls — Always Log" prose (lines 80-109) with concrete doRequest/db.QueryContext examples is gone. The 6 new rules provide equivalent, enforceable coverage including the boundary-call audit requirement in go-logging/external-call-logs-response.

  5. no-tight-loop-without-sampler threshold: "poll-loop running once per second is fine" is explicitly intentional per the rule's Why — the threshold is "would this out-pace what an operator can scan at expected load?"

  6. Index anchor alignment: All 6 anchors verified ✓

Automated checks: make precommit could not be executed due to permission restrictions, but check-index would pass since both docs/go-logging-guide.md and rules/index.json were updated together in this PR (no staleness).

{
  "verdict": "approve",
  "summary": "PR #35 bootstraps 6 well-formed RULE blocks in go-logging-guide.md covering logging quality, security, and performance. All anchors match exactly between markdown and index.json. The removed 'External Calls' prose section is replaced by machine-readable rules that provide equivalent enforceable guidance. No issues found.",
  "comments": [],
  "concerns_addressed": [
    "security: go-logging/no-sensitive-data-in-logs regex \\bkey\\b correctly does not match 'key' inside partitionKey/sortKey/lookupKey — word boundary between i and k prevents match",
    "correctness: go-logging/external-call-logs-response carve-out language 'success path or failure path, never both' is intentionally flexible — failure-only logging shown in Bad example is valid",
    "correctness: go-logging/no-log-and-return-error ast-grep is documented as 'partial pattern' — judgment tier supplements it by design",
    "correctness: removed 'External Calls — Always Log' prose (lines 80-109) replaced by 6 machine-readable rules including go-logging/external-call-logs-response which enforces boundary audit logging",
    "performance: go-logging/no-tight-loop-without-sampler 'once per second is fine' threshold is intentional — rule's Why explicitly states the judgment threshold",
    "correctness: all 6 anchors verified exact match between docs/go-logging-guide.md headings and rules/index.json"
  ]
}

@bborbe bborbe merged commit 43aa9a4 into master Jun 3, 2026
1 check passed
@bborbe bborbe deleted the feat/bootstrap-logging-rules branch June 3, 2026 05:58
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