## File: docs/architecture/pack-design.md # Pack Architecture Decisions This document captures the architectural decisions required before expanding pack coverage. It is the canonical reference for pack authors and reviewers. ## 1) REST API Pattern Detection (curl/httpie) **Decision**: Hybrid detection (keyword gate + lightweight argument parsing). - **Gate** on `curl`, `http`, or `httpie` keywords to avoid touching every command. - **Parse** method flags (`-X`, `--request`, `--method`) and extract the URL. - **Pack-specific host filters**: each pack owns its hostnames or URL prefixes. - **Decision rule**: only treat `DELETE` (and other explicitly destructive methods) as destructive when the host/path match a pack. **Rationale**: A pure keyword scan is too noisy; full AST parsing is too slow. The hybrid approach is fast, deterministic, and maintainable. ## 2) Pack Overlap Resolution **Decision**: Keep packs separate but clarify boundaries. From `git_safety_guard-qdhh`: `cicd.github_actions` is for CI operations (secrets, variables, workflows, runs). `platform.github` is for broader platform operations (repos, releases, deploy keys, webhooks, collaborators). Do not duplicate patterns across packs; document scope in pack descriptions. **Rationale**: Separation reduces regex scope and allows users to enable only what they need. Clear boundaries avoid duplication and false positives. ## 3) Command Alias Handling **Decision**: Explicit aliases for high-impact, common tools plus opt-in config. - Include **well-known aliases** in keywords (e.g., `k` for `kubectl`). - Avoid regex alias heuristics that cause false positives. - Allow **user config** to add custom aliases via pack enablement/keywords. **Rationale**: Minimizes noise while still covering common shortcuts. ## 4) Performance Budget Per Pack **Decision**: Enforce a per-pack budget and pattern cap. - **Budget**: < 500 microseconds per pack evaluation. - **Pattern cap**: < 50 total patterns per pack. - **Keywords**: minimal and specific; avoid broad single-letter keywords. **Rationale**: Keeps pack expansion from degrading hook latency. ## 5) Safe vs Destructive Threshold **Decision**: Flag-aware matching with explicit safe overrides. - **Destructive by default**: commands known to delete or destroy data (e.g., `rclone sync`, `aws s3 rm --recursive`) should be blocked even without flags. - **Flag-sensitive**: allow **dry-run/preview** flags and safe variants. - **Ambiguous commands**: only block when flags or subcommands are clearly destructive; otherwise allow with high-signal patterns. **Rationale**: Reduces false positives while still blocking dangerous actions. ## Acceptance Criteria Mapping - Decisions documented with rationale (this doc). - Performance budget defined and referenced by pack checklist. - Pack overlap resolution aligned with `git_safety_guard-qdhh`. ## Open Questions - Which alias list should be system defaults vs per-user config? - How to represent host allowlists for REST APIs in pack metadata? --- ## File: docs/design/rule-metrics-struct-mapping.md # Rule-Level Metrics: Struct Mapping & Reuse Strategy > Design document for `git_safety_guard-1dri.1` > > This document inventories existing history analytics structs and maps rule-level > metrics needs to them, ensuring no duplicate or competing analytics pipelines. --- ## Executive Summary **Finding:** The existing history analytics structs in `src/history/schema.rs` are well-designed and sufficient for rule-level metrics. No new analytics structs are needed. The `PatternEffectiveness` struct already captures per-rule metrics, and the `rule_id` field in `CommandEntry` provides stable rule identifiers. **Recommendation:** Reuse existing structs. Extend query/aggregation logic only. --- ## Struct Inventory ### Core Data Types | Struct | Location | Purpose | Rule-Metrics Relevance | |--------|----------|---------|------------------------| | `CommandEntry` | L133 | Single command record | **Primary data source** - contains `rule_id`, `pack_id`, `pattern_name`, `outcome` | | `Outcome` | L81 | Enum: Allow/Deny/Warn/Bypass | Categorizes command outcomes for metrics | ### Statistics Types | Struct | Location | Purpose | Rule-Metrics Relevance | |--------|----------|---------|------------------------| | `OutcomeStats` | L230 | Aggregate counts (allowed/denied/warned/bypassed) | Can aggregate by rule | | `PerformanceStats` | L239 | Latency percentiles (p50/p95/p99/max) | Could extend for per-rule latency | | `PatternStat` | L248 | Pattern name + count + pack_id | **Direct reuse** for top patterns | | `HistoryStats` | L325 | Complete stats for time window | Contains `top_patterns: Vec` | | `StatsTrends` | L271 | Period-over-period comparison | Extendable for rule trends | ### Analytics Types (Key for Rule-Metrics) | Struct | Location | Purpose | Rule-Metrics Relevance | |--------|----------|---------|------------------------| | `PatternEffectiveness` | L2177 | Per-pattern metrics with bypass analysis | **PERFECT FIT** - use directly | | `PotentialGap` | L2195 | Dangerous commands that were allowed | Coverage gap analysis | | `RecommendationType` | L2208 | Enum: RelaxPattern/EnablePack/etc. | Tuning recommendations | | `PackRecommendation` | L2225 | Actionable recommendation with config | Extend for rule-specific recs | | `PackEffectivenessAnalysis` | L2246 | Complete analysis result | Already groups by pattern | --- ## Rule Identifier Design The `rule_id` is already defined in `CommandEntry`: ```rust /// Stable rule identifier: `pack_id:pattern_name` /// Present only for denied commands that matched a pattern. /// Format: "core.git:reset-hard", "core.filesystem:rm-rf-root" pub rule_id: Option, ``` **Key methods in `CommandEntry`:** - `compute_rule_id()` → Constructs `pack_id:pattern_name` - `get_rule_id()` → Returns stored or computed value - `ensure_rule_id()` → Sets `rule_id` if computable This provides stable, human-readable identifiers for: - Allowlisting specific rules - Aggregating metrics per rule - Tracking rule effectiveness over time --- ## PatternEffectiveness: The Core Struct This struct is the foundation for rule-level metrics: ```rust pub struct PatternEffectiveness { /// Pattern name (e.g., "reset-hard") pub pattern: String, /// Pack ID the pattern belongs to (e.g., "core.git") pub pack_id: Option, /// Total times this pattern triggered (deny + bypass) pub total_triggers: u64, /// Times the pattern blocked a command (deny) pub denied_count: u64, /// Times the pattern was bypassed (allow-once) pub bypassed_count: u64, /// Bypass rate as a percentage (0.0-100.0) pub bypass_rate: f64, } ``` **Mapping to rule_id:** `rule_id = {pack_id}:{pattern}` **Already computed in `PackEffectivenessAnalysis`:** - `high_value_patterns: Vec` - High volume, low bypass - `potentially_aggressive: Vec` - High bypass rate --- ## Reuse vs Extend Analysis ### Direct Reuse (No Changes) | Struct | Usage | |--------|-------| | `CommandEntry` | Query by `rule_id` for per-rule history | | `PatternEffectiveness` | Per-rule metrics with bypass analysis | | `PatternStat` | Simple name+count for top rules | | `OutcomeStats` | Aggregate outcomes per rule | ### Extend (Add Fields/Methods) | Struct | Extension | Reason | |--------|-----------|--------| | `PatternEffectiveness` | Add `first_seen_ts`, `last_seen_ts` | Track rule activity timeline | | `PatternEffectiveness` | Add `projects: Vec` | See which projects trigger rule | | `PackEffectivenessAnalysis` | Add `per_rule_metrics: HashMap` | Direct rule_id lookup | ### Do NOT Create To avoid competing pipelines, these should **NOT** be created: - ~~`RuleMetrics`~~ → Use `PatternEffectiveness` - ~~`RuleEffectiveness`~~ → Use `PatternEffectiveness` - ~~`RuleStats`~~ → Use `PatternStat` with pack_id - ~~`RuleAnalysis`~~ → Use `PackEffectivenessAnalysis` --- ## Query Patterns for Rule-Level Metrics ### Per-Rule Trigger Count ```sql SELECT rule_id, COUNT(*) as triggers FROM commands WHERE rule_id IS NOT NULL GROUP BY rule_id ORDER BY triggers DESC; ``` ### Per-Rule Bypass Rate ```sql SELECT rule_id, COUNT(*) as total, SUM(CASE WHEN outcome = 'deny' THEN 1 ELSE 0 END) as denied, SUM(CASE WHEN outcome = 'bypass' THEN 1 ELSE 0 END) as bypassed, (bypassed * 100.0 / total) as bypass_rate FROM commands WHERE rule_id IS NOT NULL GROUP BY rule_id; ``` ### Rule Activity Over Time ```sql SELECT rule_id, date(timestamp) as day, COUNT(*) as triggers FROM commands WHERE rule_id IS NOT NULL GROUP BY rule_id, day ORDER BY rule_id, day; ``` --- ## Implementation Guidance ### For `dcg history stats --rule ` 1. Query `commands` table filtered by `rule_id` 2. Compute `OutcomeStats` from results 3. Return `PatternEffectiveness` struct populated from query 4. No new structs needed ### For `dcg history analyze` The existing `PackEffectivenessAnalysis` already computes `PatternEffectiveness` for each pattern. To add rule-level access: 1. Add `rule_id` to `PatternEffectiveness` (computed from pack_id + pattern) 2. Add `by_rule_id: HashMap` to analysis result 3. No new analysis pipeline needed ### For Rule-Specific Recommendations Extend `PackRecommendation` with: ```rust /// Rule ID this recommendation targets (if rule-specific) #[serde(skip_serializing_if = "Option::is_none")] pub rule_id: Option, ``` --- ## Acceptance Criteria Verification | Criterion | Status | Evidence | |-----------|--------|----------| | Rule-metrics design references existing structs | ✅ | Uses `PatternEffectiveness`, `PatternStat`, `CommandEntry` | | No duplicate analytics pipelines | ✅ | No new `Rule*` structs proposed | | Clear mapping documented | ✅ | This document | --- ## Version History | Version | Date | Changes | |---------|------|---------| | 1.0 | 2026-01-16 | Initial design document | --- ## Related Issues - **Parent:** `git_safety_guard-1dri` (Rule-Level Metrics: Track per-rule stats) - **Blocked by:** None - **Blocks:** `git_safety_guard-1dri.2` (dcg history stats --rule)