|
| 1 | +<!-- dgc-policy-v11 --> |
| 2 | +# Dual-Graph Context Policy |
| 3 | + |
| 4 | +This project uses a local dual-graph MCP server for efficient context retrieval. |
| 5 | + |
| 6 | +## MANDATORY: Adaptive graph_continue rule |
| 7 | + |
| 8 | +**Call `graph_continue` ONLY when you do NOT already know the relevant files.** |
| 9 | + |
| 10 | +### Call `graph_continue` when: |
| 11 | +- This is the first message of a new task / conversation |
| 12 | +- The task shifts to a completely different area of the codebase |
| 13 | +- You need files you haven't read yet in this session |
| 14 | + |
| 15 | +### SKIP `graph_continue` when: |
| 16 | +- You already identified the relevant files earlier in this conversation |
| 17 | +- You are doing follow-up work on files already read (verify, refactor, test, docs, cleanup, commit) |
| 18 | +- The task is pure text (writing a commit message, summarising, explaining) |
| 19 | + |
| 20 | +**If skipping, go directly to `graph_read` on the already-known `file::symbol`.** |
| 21 | + |
| 22 | +## When you DO call graph_continue |
| 23 | + |
| 24 | +1. **If `graph_continue` returns `needs_project=true`**: call `graph_scan` with `pwd`. Do NOT ask the user. |
| 25 | + |
| 26 | +2. **If `graph_continue` returns `skip=true`**: fewer than 5 files — read only specifically named files. |
| 27 | + |
| 28 | +3. **Read `recommended_files`** using `graph_read`. |
| 29 | + - Always use `file::symbol` notation (e.g. `src/auth.ts::handleLogin`) — never read whole files. |
| 30 | + - `recommended_files` entries that already contain `::` must be passed verbatim. |
| 31 | + |
| 32 | +4. **Obey confidence caps:** |
| 33 | + - `confidence=high` → Stop. Do NOT grep or explore further. |
| 34 | + - `confidence=medium` → `fallback_rg` at most `max_supplementary_greps` times, then `graph_read` at most `max_supplementary_files` more symbols. Stop. |
| 35 | + - `confidence=low` → same as medium. Stop. |
| 36 | + |
| 37 | +## Session State (compact, update after every turn) |
| 38 | + |
| 39 | +Maintain a short JSON block in your working memory. Update it after each turn: |
| 40 | + |
| 41 | +```json |
| 42 | +{ |
| 43 | + "files_identified": ["path/to/file.py"], |
| 44 | + "symbols_changed": ["module::function"], |
| 45 | + "fix_applied": true, |
| 46 | + "features_added": ["description"], |
| 47 | + "open_issues": ["one-line note"] |
| 48 | +} |
| 49 | +``` |
| 50 | + |
| 51 | +Use this state — not prose summaries — to remember what's been done across turns. |
| 52 | + |
| 53 | +## Token Usage |
| 54 | + |
| 55 | +A `token-counter` MCP is available for tracking live token usage. |
| 56 | + |
| 57 | +- Before reading a large file: `count_tokens({text: "<content>"})` to check cost first. |
| 58 | +- To show running session cost: `get_session_stats()` |
| 59 | +- To log completed task: `log_usage({input_tokens: N, output_tokens: N, description: "task"})` |
| 60 | + |
| 61 | +## Rules |
| 62 | + |
| 63 | +- Do NOT use `rg`, `grep`, or bash file exploration before calling `graph_continue` (when required). |
| 64 | +- Do NOT do broad/recursive exploration at any confidence level. |
| 65 | +- `max_supplementary_greps` and `max_supplementary_files` are hard caps — never exceed them. |
| 66 | +- Do NOT call `graph_continue` more than once per turn. |
| 67 | +- Always use `file::symbol` notation with `graph_read` — never bare filenames. |
| 68 | +- After edits, call `graph_register_edit` with changed files using `file::symbol` notation. |
| 69 | + |
| 70 | +## Context Store |
| 71 | + |
| 72 | +Whenever you make a decision, identify a task, note a next step, fact, or blocker during a conversation, append it to `.dual-graph/context-store.json`. |
| 73 | + |
| 74 | +**Entry format:** |
| 75 | +```json |
| 76 | +{"type": "decision|task|next|fact|blocker", "content": "one sentence max 15 words", "tags": ["topic"], "files": ["relevant/file.ts"], "date": "YYYY-MM-DD"} |
| 77 | +``` |
| 78 | + |
| 79 | +**To append:** Read the file → add the new entry to the array → Write it back → call `graph_register_edit` on `.dual-graph/context-store.json`. |
| 80 | + |
| 81 | +**Rules:** |
| 82 | +- Only log things worth remembering across sessions (not every minor detail) |
| 83 | +- `content` must be under 15 words |
| 84 | +- `files` lists the files this decision/task relates to (can be empty) |
| 85 | +- Log immediately when the item arises — not at session end |
| 86 | + |
| 87 | +## Session End |
| 88 | + |
| 89 | +When the user signals they are done (e.g. "bye", "done", "wrap up", "end session"), proactively update `CONTEXT.md` in the project root with: |
| 90 | +- **Current Task**: one sentence on what was being worked on |
| 91 | +- **Key Decisions**: bullet list, max 3 items |
| 92 | +- **Next Steps**: bullet list, max 3 items |
| 93 | + |
| 94 | +Keep `CONTEXT.md` under 20 lines total. Do NOT summarize the full conversation — only what's needed to resume next session. |
| 95 | + |
| 96 | +--- |
| 97 | + |
| 98 | +# Coding Standards |
| 99 | + |
| 100 | +## General |
| 101 | + |
| 102 | +Write C# code that maximises readability, maintainability, and correctness while minimising complexity and coupling. Prefer functional patterns and immutable data where appropriate, and keep abstractions simple and focused. |
| 103 | + |
| 104 | +- Write clear, self-documenting code |
| 105 | +- Keep abstractions simple and focused |
| 106 | +- Minimise dependencies and coupling |
| 107 | +- Use modern C# features appropriately |
| 108 | +- Use the repository pattern with Dapper at the repository layer for SQL Server and PostgreSQL database communication |
| 109 | + |
| 110 | +## Code Organisation |
| 111 | + |
| 112 | +**Use meaningful names — no unclear abbreviations:** |
| 113 | +```csharp |
| 114 | +// Good |
| 115 | +public async Task<Result<Order>> ProcessOrderAsync(OrderRequest request, CancellationToken cancellationToken) |
| 116 | + |
| 117 | +// Avoid |
| 118 | +public async Task<Result<T>> ProcAsync<T>(ReqDto r, CancellationToken ct) |
| 119 | +``` |
| 120 | + |
| 121 | +**Separate state from behaviour:** |
| 122 | +```csharp |
| 123 | +// Good |
| 124 | +public sealed record Order(OrderId Id, List<OrderLine> Lines); |
| 125 | + |
| 126 | +public static class OrderOperations |
| 127 | +{ |
| 128 | + public static decimal CalculateTotal(Order order) => |
| 129 | + order.Lines.Sum(line => line.Price * line.Quantity); |
| 130 | +} |
| 131 | +``` |
| 132 | + |
| 133 | +**Prefer pure methods — avoid hidden side effects:** |
| 134 | +```csharp |
| 135 | +// Good |
| 136 | +public static decimal CalculateTotalPrice(IEnumerable<OrderLine> lines, decimal taxRate) => |
| 137 | + lines.Sum(line => line.Price * line.Quantity) * (1 + taxRate); |
| 138 | + |
| 139 | +// Avoid |
| 140 | +public void CalculateAndUpdateTotalPrice() |
| 141 | +{ |
| 142 | + this.Total = this.Lines.Sum(l => l.Price * l.Quantity); |
| 143 | + this.UpdateDatabase(); |
| 144 | +} |
| 145 | +``` |
| 146 | + |
| 147 | +**Use extension methods for domain-specific operations:** |
| 148 | +```csharp |
| 149 | +public static class OrderExtensions |
| 150 | +{ |
| 151 | + public static bool CanBeFulfilled(this Order order, Inventory inventory) => |
| 152 | + order.Lines.All(line => inventory.HasStock(line.ProductId, line.Quantity)); |
| 153 | +} |
| 154 | +``` |
| 155 | + |
| 156 | +**Design for testability — avoid hidden dependencies:** |
| 157 | +```csharp |
| 158 | +// Good: pure, easily testable |
| 159 | +public static decimal CalculateDiscount(decimal price, int quantity, CustomerTier tier) => ... |
| 160 | + |
| 161 | +// Avoid: hidden service calls make this impossible to unit test |
| 162 | +public decimal CalculateDiscount() |
| 163 | +{ |
| 164 | + var user = _userService.GetCurrentUser(); |
| 165 | + var settings = _configService.GetSettings(); |
| 166 | + ... |
| 167 | +} |
| 168 | +``` |
| 169 | + |
| 170 | +## Dependency Management |
| 171 | + |
| 172 | +**Minimise constructor injection — too many dependencies signal a design problem:** |
| 173 | +```csharp |
| 174 | +// Good |
| 175 | +public sealed class OrderProcessor(IOrderRepository repository) { } |
| 176 | + |
| 177 | +// Avoid |
| 178 | +public class OrderProcessor( |
| 179 | + IOrderRepository repository, |
| 180 | + ILogger logger, |
| 181 | + IEmailService emailService, |
| 182 | + IMetrics metrics, |
| 183 | + IValidator validator) { } |
| 184 | +``` |
| 185 | + |
| 186 | +**Prefer composition via interfaces:** |
| 187 | +```csharp |
| 188 | +public sealed class EnhancedLogger(ILogger baseLogger, IMetrics metrics) : ILogger { } |
| 189 | +``` |
0 commit comments