Skip to content

Commit de853d6

Browse files
committed
RE1-T105 Fixing issues with routes.
1 parent 5e8c9ea commit de853d6

27 files changed

Lines changed: 2604 additions & 28 deletions

CLAUDE.md

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
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+
```

Core/Resgrid.Localization/Areas/User/Routes/Routes.en.resx

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,10 @@
8888
<value>New Route</value>
8989
</data>
9090
<data name="ActiveRoutes" xml:space="preserve">
91-
<value>Active Routes</value>
91+
<value>In Progress</value>
92+
</data>
93+
<data name="ArchivedRoutes" xml:space="preserve">
94+
<value>Archived Routes</value>
9295
</data>
9396
<data name="Stops" xml:space="preserve">
9497
<value>Stops</value>
@@ -135,20 +138,38 @@
135138
</data>
136139
<!-- ActiveRoutes -->
137140
<data name="ActiveRoutesPageTitle" xml:space="preserve">
138-
<value>Active Routes</value>
141+
<value>In Progress Routes</value>
139142
</data>
140143
<data name="ActiveRoutesHeader" xml:space="preserve">
141-
<value>Active Routes</value>
144+
<value>In Progress Routes</value>
142145
</data>
143146
<data name="ActiveBreadcrumb" xml:space="preserve">
144-
<value>Active</value>
147+
<value>In Progress</value>
145148
</data>
146149
<data name="NoActiveRoutes" xml:space="preserve">
147-
<value>No Active Routes</value>
150+
<value>No Routes In Progress</value>
148151
</data>
149152
<data name="NoActiveRoutesMessage" xml:space="preserve">
150153
<value>There are no route instances currently in progress.</value>
151154
</data>
155+
<data name="ArchivedRoutesPageTitle" xml:space="preserve">
156+
<value>Archived Routes</value>
157+
</data>
158+
<data name="ArchivedRoutesHeader" xml:space="preserve">
159+
<value>Archived Routes</value>
160+
</data>
161+
<data name="ArchivedBreadcrumb" xml:space="preserve">
162+
<value>Archived</value>
163+
</data>
164+
<data name="NoArchivedRoutes" xml:space="preserve">
165+
<value>No Archived Routes</value>
166+
</data>
167+
<data name="NoArchivedRoutesMessage" xml:space="preserve">
168+
<value>There are no archived route plans.</value>
169+
</data>
170+
<data name="ArchivedRouteDetailPageTitle" xml:space="preserve">
171+
<value>Archived Route Detail</value>
172+
</data>
152173
<data name="UnitLabel" xml:space="preserve">
153174
<value>Unit</value>
154175
</data>

Core/Resgrid.Model/Services/IRouteService.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,10 @@ public interface IRouteService
5454

5555
// Geofence
5656
Task<RouteInstanceStop> CheckGeofenceProximityAsync(int unitId, decimal latitude, decimal longitude);
57+
58+
// Single-record lookups
59+
Task<RouteStop> GetRouteStopByIdAsync(string routeStopId);
60+
Task<RouteInstanceStop> GetInstanceStopByIdAsync(string routeInstanceStopId);
61+
Task<RouteInstanceStop> UpdateInstanceStopNotesAsync(string routeInstanceStopId, string notes, CancellationToken cancellationToken = default);
5762
}
5863
}

Core/Resgrid.Services/RouteService.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,31 @@ public async Task<RoutePlan> UpdateRouteGeometryAsync(string routePlanId, string
415415

416416
#endregion Mapbox Integration
417417

418+
#region Single-record lookups
419+
420+
public async Task<RouteStop> GetRouteStopByIdAsync(string routeStopId)
421+
{
422+
return await _routeStopsRepository.GetByIdAsync(routeStopId);
423+
}
424+
425+
public async Task<RouteInstanceStop> GetInstanceStopByIdAsync(string routeInstanceStopId)
426+
{
427+
return await _routeInstanceStopsRepository.GetByIdAsync(routeInstanceStopId);
428+
}
429+
430+
public async Task<RouteInstanceStop> UpdateInstanceStopNotesAsync(string routeInstanceStopId, string notes, CancellationToken cancellationToken = default)
431+
{
432+
var instanceStop = await _routeInstanceStopsRepository.GetByIdAsync(routeInstanceStopId);
433+
if (instanceStop == null)
434+
throw new ArgumentException("Route instance stop not found.", nameof(routeInstanceStopId));
435+
436+
instanceStop.Notes = notes;
437+
await _routeInstanceStopsRepository.SaveOrUpdateAsync(instanceStop, cancellationToken);
438+
return instanceStop;
439+
}
440+
441+
#endregion Single-record lookups
442+
418443
#region Geofence
419444

420445
public async Task<RouteInstanceStop> CheckGeofenceProximityAsync(int unitId, decimal latitude, decimal longitude)

0 commit comments

Comments
 (0)