feat(rules): bootstrap 3 doc families (service-impl, k8s-crd, functional-options)#18
Conversation
…nal-options) Second multi-doc bootstrap PR — same shape as PR #17. 3 docs (~500-770 lines), 6 rules, single bot review cycle. Rules added (rules/index.json: 62 -> 68): go-service-impl/* (owner: go-architecture-assistant) - no-context-object-injection (MUST) — never bundle deps in a *Context / *Deps struct passed through methods. Constructor injection makes the dep set visible at the type signature and minimal in scope. - provider-vs-registry-choice (SHOULD) — static switch for fixed compile-time sets (< ~10 types); map-based registry only for runtime extensible / plugin systems. go-k8s-crd/* (owner: go-architecture-assistant) - use-bborbe-k8s (SHOULD) — collapse ~300 lines of hand-written event-handler + adapter + store boilerplate into k8s.NewEventHandler[T] + k8s.NewResourceEventHandler[T] from github.com/bborbe/k8s. - generated-client-not-dynamic (MUST) — first-party CRDs use the typed clientset from hack/update-codegen.sh, not client-go/dynamic. Dynamic client is for unknown schemas (admin tools, generic operators); known-schema use throws away every type-safety guarantee. go-functional-options/* (owner: go-quality-assistant) - singular-option-type (SHOULD) — XxxOption (singular fn type) + XxxOptions (plural struct). Industry-standard pair-naming. - with-prefix-option-functions (SHOULD) — option constructors prefixed With*. Uniform prefix makes the option-list call site self-describing. CLAUDE.md doc-agent table updated with all 3 new mappings. Pre-emptive checks (lessons from PRs #6, #8, #14, #17): - No personal vault paths - One trading-domain leak introduced in my service-impl example (ProcessMarket/Limit/Stop — order-type terminology) caught by pre-push grep + genericised to ProcessImage/Video/Document. Pre-existing OrderType/MarketOrder/LimitOrder/StopOrder references in the original doc are NOT changed in this PR (out of scope; the bot may flag them as pre-existing). - All 6 rule IDs unique against 62 existing entries - All 3 owner agents exist - make build-index regenerated; check-index passes
There was a problem hiding this comment.
Now I have all the data needed for the consolidated report. Let me compile the final JSON verdict:
{
"verdict": "request-changes",
"summary": "The PR adds 3 new doc families with 6 new rules correctly registered in rules/index.json and mapped in CLAUDE.md. However, two critical issues were found: the go-service-implementation-patterns.md examples use raw http.HandlerFunc return types that contradict the established go-http-handler-refactoring-guide.md (which requires libhttp.WithError), appearing in both the Bad and the Good example sections; and the Factory Pattern Implementation example at lines 301-308 has a non-exhaustive switch without a default case that returns (nil, nil), creating a nil panic risk. Additionally, CreateSaramaConfig at docs/go-functional-options-pattern.md:108 uses the Create* factory prefix while returning an error and containing a loop in the body — violating the very factory rules this doc is teaching.",
"comments": [
{
"file": "docs/go-service-implementation-patterns.md",
"line": 456,
"severity": "critical",
"message": "go-service-impl/MUST: The 'Bad' example at line 456 returns http.HandlerFunc, which directly contradicts docs/go-http-handler-refactoring-guide.md (lines 46-77, 282-318) that requires libhttp.WithError for HTTP handlers. Both Bad and Good examples in this section return raw http.HandlerFunc — the Good example should return libhttp.WithError and be placed in pkg/handler/ per the established HTTP handler refactoring guide."
},
{
"file": "docs/go-service-implementation-patterns.md",
"line": 500,
"severity": "critical",
"message": "go-service-impl/MUST: The 'Good' example at line 500 returns http.HandlerFunc, directly contradicting the go-http-handler-refactoring-guide.md which mandates libhttp.WithError (or libhttp.WithErrorTx for DB transactions). The section presents this as the correct pattern but it violates the HTTP handler architecture rules. Fix: use libhttp.WithError return type and place in pkg/handler/ with factory wiring."
},
{
"file": "docs/go-service-implementation-patterns.md",
"line": 301,
"severity": "critical",
"message": "go-service-impl/no-context-object-injection MUST: The switch in 'Factory Pattern Implementation' lacks a default: case returning an error. For a function returning (UserService, error), omitting default causes the compiler to infer return nil, nil — a nil panic at runtime when an unknown UserType is passed. The 'Good' example at lines 82-91 correctly uses default: errors.Errorf; the Factory Pattern Implementation example does not."
},
{
"file": "docs/go-functional-options-pattern.md",
"line": 108,
"severity": "major",
"message": "go-factory-pattern MUST (go-factory/no-error-return + go-factory/no-conditional-in-body): CreateSaramaConfig uses the Create* prefix (factory convention) while returning error AND containing a for loop to apply options. This violates two MUST-level factory rules. Since the doc teaches the functional-options pattern to readers who may copy this into pkg/factory/, they will trip both rules. Rename to NewSaramaConfig (constructor convention) or clarify this is not a factory.go function."
},
{
"file": "docs/go-kubernetes-crd-controller-guide.md",
"line": 6,
"severity": "major",
"message": "go-k8s-crd/use-bborbe-k8s SHOULD: The RULE block is inserted at the very top of 'Section 0. Before you start' before the bborbe/k8s API bullet list (line 32) that explains what k8s.NewEventHandler and k8s.NewResourceEventHandler actually are. The Good example calls these functions before the reader knows what they do. Move the RULE block to after the API list, or add a forward reference."
},
{
"file": "docs/go-kubernetes-crd-controller-guide.md",
"line": 85,
"severity": "major",
"message": "go-k8s-crd/generated-client-not-dynamic MUST: The RULE block is placed as a subsection of '## 2. Repository layout' (CRD library layout) but the rule applies to the consumer/ controller side, not the CRD library. This misplacement will confuse readers about which part of the repo the rule targets. Reposition to the consumer service section."
},
{
"file": "docs/go-functional-options-pattern.md",
"line": 519,
"severity": "major",
"message": "go-functional-options/singular-option-type SHOULD: The enforcement description uses 'wrong-singular pattern' and 'violates' language that implies a definitive error, but the doc's own pre-existing content (line 588) marks the same pattern as 'Acceptable but less clear' — a preference, not a violation. The SHOULD level is correct but the wording is too strong. Use 'suboptimal naming' instead of 'wrong-singular pattern' to align with the doc's existing stance."
},
{
"file": "docs/go-service-implementation-patterns.md",
"line": 212,
"severity": "major",
"message": "go-service-impl/no-context-object-injection MUST: The Enforcement description says '*<Name>Context' / '*<Name>Deps' (pointer types only) but the Bad example passes svcCtx ServiceContext as a value, not a pointer. The enforcement would miss the value-passed case shown in the example. Either update enforcement to also match value types, or update the Bad example to pass *ServiceContext to match the enforcement description."
},
{
"file": "docs/go-functional-options-pattern.md",
"line": 203,
"severity": "nit",
"message": "go-functional-options/singular-option-type SHOULD: The 'Options with Validation' example returns func(*ConsumerOptions) as an inline type, but the new singular-option-type RULE promotes custom named types like ConsumerOption. Multiple existing examples in the 'Advanced Patterns' section (lines 203, 220, 232, 245, 268, 691, 697, 703) use inline func(*XxxOptions) instead of the named XxxOption type. Consider using named types consistently in the 'Good' examples to model the recommended pattern."
},
{
"file": "docs/go-functional-options-pattern.md",
"line": 550,
"severity": "nit",
"message": "go-functional-options/with-prefix-option-functions SHOULD: The Enforcement mentions function_declaration returning *Option or *ConfigFunc, but the Applies when also mentions bare nouns like BatchSize(n) with no suffix. The enforcement description doesn't explain how bare nouns are distinguished from unrelated functions that return a func type. Clarify in the enforcement description how bare nouns are detected."
}
],
"concerns_addressed": [
"correctness: rules/index.json - 6 new rules verified: all IDs unique against 62 prior entries, all owner agents (go-architecture-assistant, go-quality-assistant) exist in agents/ directory — CONCERN ADDRESSED",
"correctness: docs/go-service-implementation-patterns.md - go-service-impl/no-context-object-injection ast-grep pattern correctly identifies struct-field-bundle anti-pattern, but enforcement description has a pointer/value type mismatch with its own Bad example — RAISED as critical comment",
"correctness: docs/go-kubernetes-crd-controller-guide.md - go-k8s-crd/generated-client-not-dynamic dynamic client smell is well-described; 'first-party CRD' boundary is clear from the enforcement description (schema known at compile time = first-party) — CONCERN ADDRESSED",
"correctness: docs/go-functional-options-pattern.md - go-functional-options/singular-option-type ast-grep pattern on type_alias_declaration/type_declaration correctly distinguishes singular vs plural naming — CONCERN ADDRESSED",
"tests: rules/index.json - index.json schema is consistent with existing entries; make precommit could not be verified in this environment (sandbox) — UNABLE TO VERIFY (needs CI run)",
"correctness: CLAUDE.md - doc-agent table correctly maps go-service-implementation-patterns.md → go-architecture-assistant, go-kubernetes-crd-controller-guide.md → go-architecture-assistant, go-functional-options-pattern.md → go-quality-assistant — CONCERN ADDRESSED"
]
}Bot raised 3 CRITICAL + 5 MAJOR + 2 NIT. Mix of issues I introduced (fixing) and pre-existing problems in the affected docs (deferring to focused follow-ups rather than inflating this PR's scope). FIXED (issues I introduced): - no-context-object-injection: enforcement said '*<Name>Context' (pointer-only) but my Bad example uses value-passed 'svcCtx ServiceContext'. Updated enforcement to match both shapes. - use-bborbe-k8s rule block placement: was at the top of section 0 before the bullet list explaining what k8s.NewEventHandler / k8s.NewResourceEventHandler do. Moved to AFTER the bullet list so the Good example doesn't reference undefined functions. - generated-client-not-dynamic rule block placement: was under section 2 (Repository layout / CRD library subsection), but the rule scopes to the consumer side. Moved to section 4 (K8sConnector interface, consumer side) where the dynamic-client smell actually lives. - singular-option-type wording: 'wrong-singular pattern' was too strong for a SHOULD rule. Reworded as 'suboptimal pair naming'; noted both shapes work and the rule promotes the industry-standard pair for clarity, not as a correctness fix. Aligns with the doc's pre-existing 'Acceptable but less clear' framing of the alternative naming. NOT FIXED (pre-existing in the affected docs, out of this PR's scope): - go-service-implementation-patterns.md HTTP handler examples (lines 456, 500) return raw http.HandlerFunc instead of libhttp.WithError. Pre-existing — not introduced by this PR's 2 rule blocks. Should be a focused follow-up that either fixes the examples or replaces the section with a cross-reference to go-http-handler-refactoring-guide.md. - go-service-implementation-patterns.md Factory Pattern Implementation switch (lines 301-308) lacks a default case — nil panic risk. Pre-existing. Follow-up should add the default returning errors.Errorf, matching the Good example in the Decision Framework section earlier in the same doc. - go-functional-options-pattern.md CreateSaramaConfig (line 108) uses Create* factory prefix while returning error AND containing a for loop — violates go-factory/no-error-return and go-factory/no-conditional-in-body. Pre-existing. Follow-up should rename to NewSaramaConfig (constructor convention) or clarify it's not a factory.go function. The 2 NITs (inline-typed option functions vs named XxxOption type in advanced-patterns examples; bare-noun-detection in enforcement description) are skipped — not blocking, can be addressed in a follow-up doc-polish pass. make build-index regenerated; check-index passes.
superseded by new automated review
There was a problem hiding this comment.
Now I have all the data needed. Let me compile the consolidated report and emit the final verdict.
Consolidated PR Review Report
PR: feat(rules): bootstrap 3 doc families (service-impl, k8s-crd, functional-options)
Branch: feat/bootstrap-3doc2 → master
Files changed: 5 files, 266 insertions
Automated Checks
- LICENSE file: Present ✅
- make precommit: Could not execute (permission denied in environment) — noted, not blocking
MUST FIX (Critical)
None. No critical issues found.
SHOULD FIX (Important)
1. docs/go-functional-options-pattern.md line ~526 — Bad example is syntactically misleading
The go-functional-options/singular-option-type Bad example shows type ConsumerOptions func(*ConsumerOptions) with the comment "and the struct is also ConsumerOptions?". In Go, you cannot have two top-level declarations with the same name in the same package — this is a compile error. The intent (name collision between type alias and struct) is not actually demonstrated by code that won't compile. A real collision would involve different names (e.g., type ConsumerOptionsFunc func(*ConsumerOptions) paired with type ConsumerOptions struct{...}). The example should be fixed or the comment clarified.
2. docs/go-service-implementation-patterns.md line ~31 — func init() in Bad example not cross-referenced
The go-service-impl/provider-vs-registry-choice Bad example uses func init() to register processors, which simultaneously violates go-architecture/no-globals-or-singletons (MUST). Readers who encounter only this rule block may miss that init() is independently a MUST violation. Consider adding a brief cross-reference note in the Bad section.
NICE TO HAVE (Optional)
3. docs/go-service-implementation-patterns.md line ~230 — Good example references undeclared emailService struct
The go-service-impl/no-context-object-injection Good example shows return &emailService{...} but the type emailService struct{...} definition is omitted. Adding the struct definition would make the example self-contained and better demonstrate the private-struct-matches-interface pattern.
4. All 6 new rules lack rules/go/*.yml ast-grep files
This is consistent with the repo's existing state (only ~16 of 61 Go rules have mechanical YAML enforcement), but it's worth tracking: the enforcement field for all 6 rules says "judgment" / "ast-grep follow-up", meaning no mechanical enforcement exists yet. Not actionable in this PR, but worth a future pass.
Manual Review Notes
- All 6
rules/index.jsonentries are well-formed with correct schema (7 required fields present, alphabetical ordering correct) anchorequalsidverbatim for all 6 entries ✅- All
ownervalues inindex.jsonmatch theAgentcolumn in the updatedCLAUDE.mdalignment table ✅ - All 3 new doc rows in
CLAUDE.mdtable are correct ✅ - No contradictions found between new doc content and existing
go-http-handler-refactoring-guide.mdpatterns ✅
Verdict
This is a clean, low-risk PR. The 2 important issues are documentation-accuracy concerns (a compile-error example and a missing cross-reference), not structural or correctness bugs. The 6 new rule entries in rules/index.json are all correct and consistent.
{
"verdict": "request-changes",
"summary": "PR #18 bootstraps 3 new rule families (service-impl, k8s-crd, functional-options) with properly registered index.json entries and aligned CLAUDE.md table. Two SHOULD-level documentation issues were found: the Bad example in go-functional-options/singular-option-type contains code that would not compile in Go (same-name collision is a compile error), and the go-service-impl/provider-vs-registry-choice Bad example uses func init() without cross-referencing the separate no-globals-or-singletons MUST rule. Neither is a structural bug but both should be fixed before merge.",
"comments": [
{
"file": "docs/go-functional-options-pattern.md",
"line": 526,
"severity": "major",
"message": "go-functional-options/singular-option-type Bad example: `type ConsumerOptions func(*ConsumerOptions)` cannot compile in Go — you cannot shadow a type name with another declaration in the same package. The intent (naming collision) is correct but the example needs a real-world shape, e.g. a type alias `ConsumerOptionsFunc func(*ConsumerOptions)` paired with a struct `ConsumerOptions` — different names, same semantic collision. Fix: use two distinct identifiers that demonstrate the collision without triggering a compile error."
},
{
"file": "docs/go-service-implementation-patterns.md",
"line": 31,
"severity": "major",
"message": "go-service-impl/provider-vs-registry-choice Bad example uses `func init()` to register processors, which simultaneously violates `go-architecture/no-globals-or-singletons` (MUST level). Readers who encounter this rule block in isolation may not connect it to the independent MUST violation. Consider adding a cross-reference note in the Bad section, e.g. `// also violates go-architecture/no-globals-or-singletons`."
},
{
"file": "docs/go-service-implementation-patterns.md",
"line": 230,
"severity": "nit",
"message": "go-service-impl/no-context-object-injection Good example returns `&emailService{...}` but the `type emailService struct{...}` definition is not shown. Making the struct definition explicit would make the example self-contained and better demonstrate the private-struct-matches-interface pattern."
}
],
"concerns_addressed": [
"correctness: rules/index.json 6 new entries verified valid schema, unique IDs, correct owner agents — all pass",
"correctness: docs/go-functional-options-pattern.md new doc — structure correct, 2 RULE blocks well-formed (minor example issue flagged as SHOULD)",
"correctness: docs/go-kubernetes-crd-controller-guide.md new doc — structure correct, 2 RULE blocks well-formed, no issues found",
"correctness: docs/go-service-implementation-patterns.md new doc — structure correct, 2 RULE blocks well-formed (2 issues flagged as SHOULD/nit)",
"correctness: CLAUDE.md doc-agent table updated — all 3 new docs properly listed with correct owner agents"
]
}2 MAJOR + 1 NIT — all valid, all fixed:
MAJOR 1: singular-option-type Bad example used 'type ConsumerOptions
func(*ConsumerOptions)' which doesn't compile (duplicate declaration).
Rewrote with two compilable cases that actually demonstrate the
naming collision: function-type-plural forces struct to use Config
instead, struct-singular forces function-type to use OptionFunc
instead. Both shapes show the collision-induced split-naming.
MAJOR 2: provider-vs-registry-choice Bad example uses func init()
which simultaneously violates go-architecture/no-globals-or-singletons
(MUST). Added inline cross-reference note in the Bad example so
readers see both rule violations.
NIT: no-context-object-injection Good example referenced &emailService{...}
without showing the struct definition. Added the explicit type
declaration so the example is self-contained (also models the
private-struct-matches-interface pattern incidentally).
superseded by new automated review
There was a problem hiding this comment.
PR Review Report
PR: #18 feat(rules): bootstrap 3 doc families (service-impl, k8s-crd, functional-options)
Target: master | Source: feat/bootstrap-3doc2 (ded6b4a)
Scope: Feature bootstrap — 3 new guides + 6 new rule entries in index
Automated Checks
- LICENSE file: Present ✓
- llms.txt entries: All 3 new docs present ✓
- README.md tables: All 3 new docs present ✓
Must Fix (Critical)
None.
Should Fix (Important)
| File | Line | Issue |
|---|---|---|
docs/go-service-implementation-patterns.md |
19 | go-service-impl/provider-vs-registry-choice rule says applies_when is "a fixed compile-time set (< ~10 types)". The ~10 qualifier is ambiguous — it's unclear whether this means count-based or compile-time-extensibility-based. The prose (line 21) clarifies "closed set → switch; open set → registry" which is the right semantic distinction; the < ~10 types parenthetical adds confusion. Recommend removing the count qualifier entirely and relying solely on the closed/open set characterization. |
Nice to Have (Optional)
| File | Line | Issue |
|---|---|---|
docs/go-kubernetes-crd-controller-guide.md |
360 | Mentions ptr.To() from k8s.io/utils/ptr but the guide doesn't import or show usage of this package. Since this is a newly bootstrapped doc, consider adding a brief import note or inline example showing ptr.To(true) for the XPreserveUnknownFields call. |
docs/go-functional-options-pattern.md |
588–646 | The "Option Type Names" section covers 4 alternative naming suffixes (XxxModifier, XxxConfigFunc, etc.) beyond the recommended XxxOption. This section is informative but adds length to an already-long doc. Consider whether alternatives belong in the main doc or a separate reference section to keep the primary guidance focused. |
Plan Concerns — Resolution Status
| Concern | Status |
|---|---|
rules/index.json: 6 new entries (62→68), IDs unique, schema consistent |
Resolved — all 6 IDs unique, all owners (go-architecture-assistant, go-quality-assistant) exist |
rules/index.json: verify 3 owner agents exist |
Resolved — both owners present in agents/ |
docs/go-functional-options-pattern.md: singular/plural conventions correctly described |
Resolved — singular XxxOption / plural XxxOptions pair correctly documented throughout |
docs/go-kubernetes-crd-controller-guide.md: bborbe/k8s abstraction recommendations |
Resolved — k8s.Type, k8s.EventHandler[T], k8s.NewResourceEventHandler[T] primitives documented with correct shapes |
docs/go-service-implementation-patterns.md: provider-vs-registry sizing rule |
Resolved — rule correctly states "closed set → switch; open set → registry" |
CLAUDE.md: doc-agent table updated with 3 new docs |
Resolved — all 3 docs properly mapped to their owner agents |
rules/index.json: index well-formed JSON |
Resolved — valid JSON, 68 entries |
Summary
The PR correctly bootstraps 3 new documentation families and registers 6 new rules in rules/index.json. All doc-agent mappings in CLAUDE.md, README.md, and llms.txt are accurate. One rule (go-service-impl/provider-vs-registry-choice) has an ambiguous < ~10 types> qualifier that should be removed to avoid confusion about whether the rule is count-based vs. extensibility-based.
{
"verdict": "approve",
"summary": "PR #18 correctly bootstraps 3 new doc families (service-impl, k8s-crd, functional-options) with 6 new rule entries in rules/index.json. All doc-agent mappings in CLAUDE.md, README.md, and llms.txt are accurate and consistent. One nit: the go-service-impl/provider-vs-registry-choice rule's '< ~10 types' qualifier is ambiguous and should be removed in favor of the clearer 'closed set vs open set' prose already present.",
"comments": [
{
"file": "docs/go-service-implementation-patterns.md",
"line": 19,
"severity": "major",
"message": "go-service-impl/provider-vs-registry-choice: remove '< ~10 types' qualifier from applies_when — the rule's prose already correctly characterizes the decision as 'closed set → switch; open set → registry', which is the right semantic. The count-based qualifier creates ambiguity about whether the rule is triggered by cardinality or by compile-time vs runtime extensibility."
}
],
"concerns_addressed": [
"correctness: rules/index.json — 6 new entries (62→68) have unique IDs and consistent schema; both owner agents exist",
"correctness: docs/go-functional-options-pattern.md — singular XxxOption / plural XxxOptions pair correctly described throughout",
"correctness: docs/go-kubernetes-crd-controller-guide.md — bborbe/k8s abstraction recommendations are accurate (k8s.Type, k8s.EventHandler[T], k8s.NewResourceEventHandler[T])",
"correctness: docs/go-service-implementation-patterns.md — provider-vs-registry rule correctly states 'closed set → switch; open set → registry'",
"correctness: CLAUDE.md — all 3 new docs properly listed in doc-agent table with correct owner agents",
"tests: rules/index.json — valid JSON, 68 well-formed entries"
]
}…istry Bot approved PR #18 on ded6b4a with one MAJOR — remove the '< ~10 types' qualifier from go-service-impl/provider-vs-registry-choice. The real distinction is closed-vs-open set, not cardinality; the count-based hint creates ambiguity (does cardinality trigger the rule, or is cardinality just a proxy for the set being closed?). The rule's prose already correctly characterises the decision as closed-set→switch / open-set→registry, so the qualifier is redundant and confusing.
There was a problem hiding this comment.
Based on the comprehensive review (4 concurrent agents + automated checks), here is the consolidated report:
PR Review: feat(rules): bootstrap 3 doc families
Diff Summary
- 4 files changed: 3 Markdown docs + 1 JSON rules index
- +71 −51 lines — documentation refinements, no Go source changes
- Scope: docs-only; this is a CLAUDE.md plugin repo
Automated Checks
- ✅ LICENSE: exists at root with current year
- ✅ Precommit target: exists (would validate JSON syntax and links)
Agent Review Results
| Agent | Verdict |
|---|---|
| go-quality-assistant | Clean — JSON valid, Go snippets correct, links valid |
| go-factory-pattern-assistant | Clean — no violations, NewEmailService is textbook correct |
| go-test-coverage-assistant | Clean — rule explanations improved, no coverage gaps for doc-only changes |
| license-assistant | Clean — LICENSE present and properly formatted |
Findings
None. The diff is documentation-only with clean prose, correct Go snippets, and a properly synchronized rules/index.json.
{
"verdict": "approve",
"summary": "Clean documentation-only PR that refines 3 existing rule families (functional-options, k8s-crd, service-impl) with clearer applies_when language, better bad/good examples, and proper rule relocation in the k8s-crd guide. rules/index.json is in sync with all doc changes. No issues found.",
"comments": [],
"concerns_addressed": [
"correctness: ast-grep patterns in docs — all Go snippets verified syntactically correct by go-quality-assistant",
"correctness: no-context-object-injection pointer/value scope — addressed: applies_when now explicitly covers both shapes",
"correctness: generated-client-not-dynamic consumer scope — addressed: rule relocated to section 4 (consumer side), enforcement text updated to 'consumer service'",
"tests: no test coverage for new rules — not applicable: this is a docs-only plugin repo, not a Go service",
"correctness: singular-option-type ast-grep patterns — addressed: enforcement text clarifies this is clarity-focused, not a correctness fix"
]
}…ing) First Python-side bootstrap PR. Same multi-doc shape as PRs #17, #18. 3 Python docs (~500-820 lines), 6 rules, single bot review cycle. Expands rule coverage from Go-only to Python. Rules added (rules/index.json: 68 -> 74): python-architecture/* (owner: python-architecture-assistant) - constructor-injection-only (MUST) — deps via __init__; methods take only runtime data. Mixing the two breaks the dep-graph visibility that makes Python's typing useful. - main-py-composition-root (SHOULD) — wire all deps in main(), never at module scope. Module-level instantiation runs at import time, making tests order-dependent. python-ioc/* (owner: python-architecture-assistant) - protocol-not-abc-for-dependencies (MUST) — typing.Protocol for dependency interfaces; abc.ABC only when concrete impls share code via super(). Protocol is the right primitive for pure contracts; ABC is the right primitive for shared inheritance. - dependencies-as-private-fields (MUST) — store injected deps on self._foo (private), never self.foo (public). Public attribute storage invites external mutation that breaks the constructor- injection immutability contract. python-logging/* (owner: python-quality-assistant) - configure-once-in-main (MUST) — logging.basicConfig only at the application entry point. Libraries call logging.getLogger(__name__) and emit; they never configure. Library-side basicConfig produces three failure modes (first-import-wins, duplicate handlers, lost log-level control). - lazy-evaluation-for-debug (MUST) — use %s placeholders for DEBUG messages with expensive interpolated values, not f-strings. F-string interpolation runs every call even when DEBUG is filtered out; %s defers evaluation to the logging library. CLAUDE.md doc-agent table updated with all 3 new mappings. Generic examples throughout (User, Order, UserService, UserRepository). No personal vault paths, no trading-domain terms. Pre-emptive grep clean. make build-index regenerated; check-index passes.
…ture, makefile) Second Python-side bootstrap. Same multi-doc-per-PR shape as PRs #17, #18, #19. 3 docs (~467-576 lines), 6 rules. This time the RULE blocks REPLACE the existing constraint sections (not insert above), avoiding the redundancy issue that hit PR #19. Rules added (rules/index.json: 74 -> 80): python-pydantic/* (owner: python-quality-assistant) - boundary-validation-only (MUST) — Pydantic at system boundaries only (API, queue ingestion, file parser); internal domain types use dataclass / plain types to avoid validation overhead on trusted data. - optional-needs-default (MUST) — Optional[T] alone is NOT omittable; it's a type-system 'T or None'. Pair with '= None' (or Field(default=...)) when the intent is 'may be omitted'. python-project-structure/* (owner: python-architecture-assistant) - src-layout-required (MUST) — packages live in src/, not at repo root. Root layout silently picks up the dev directory via sys.path; src/ forces 'install then import' which surfaces packaging bugs. - pyproject-toml-with-hatchling (MUST) — pyproject.toml + hatchling build backend, never setup.py. PEP 517/518 declarative manifest; hatchling is the recommended PyPA backend. python-makefile/* (owner: python-quality-assistant) - precommit-target-required (MUST) — every Python project's Makefile has a precommit target running format + test + check. Project- agnostic uniform entry point for CI scripts and pre-commit hooks. - uv-not-pip-or-poetry (SHOULD) — uv for dependency management (10-100x faster than pip/poetry/pipenv, deterministic uv.lock, reads standard PEP 621 metadata). SHOULD level acknowledges legacy projects mid-migration. CLAUDE.md doc-agent table updated with all 3 new mappings. Generic examples (User, Product, iphone_backup package, etc). No personal vault paths, no trading-domain terms. make build-index regenerated; check-index passes.
…ncy) Third multi-doc batch shape (after PRs #17, #18, #21). 3 small Go docs (84-148 lines each), 4 rules. Bot review on one cycle. Rules added (rules/index.json: 80 -> 84): go-mod-replace/* (owner: go-quality-assistant) - no-cross-repo-replace (MUST) — replace directives must not point outside the current repo's working tree. Off-repo replaces only work on the author's machine; CI breaks; module graph becomes non-reproducible. Same-repo monorepo replaces ARE correct and remain exempt. go-glog/* (owner: go-quality-assistant) - use-v-for-debug-not-info (MUST) — V0 (bare glog.Info) is the always-on production level; debug/trace/internal-state logs use glog.V(1+). Inverting the levels produces gigabytes of noise in production and requires a deploy to change verbosity for troubleshooting. (Rule ID is all-lowercase per build-index.py regex '[a-z0-9-]+/[a-z0-9-]+' — initial attempt with capital V was rejected; walker caught it before push.) go-concurrency/* (owner: go-architecture-assistant) - no-raw-go-func (MUST) — never use 'go func()' outside main.go entry points; use github.com/bborbe/run strategies (CancelOnFirstErrorWait, All, Sequential). Raw goroutines leak, race, and require hand-rolled sync.WaitGroup that drift toward deadlocks. - channel-closed-by-sender-only (MUST) — only the producer closes a channel. Closing from the receiver side panics on still-pending sends; receivers use 'for v := range ch' or comma-ok idiom. CLAUDE.md doc-agent table updated. Generic examples throughout. No personal vault paths, no trading- domain terms. Pre-emptive grep clean. make build-index regenerated; check-index passes.
Summary
Second multi-doc bootstrap PR after PR #17 validated the pattern. 3 docs (~500-770 lines), 6 rules, single bot review cycle.
`rules/index.json`: 62 → 68 entries (3 new families).
Rules added
Notable from this PR
Pre-push checks
Test plan