From 6b478a1ffb0e66fa945846ad66d256c42e216d82 Mon Sep 17 00:00:00 2001 From: Derek Gabriel Date: Sun, 12 Apr 2026 17:34:56 -1000 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20move=20touch=20endpoint=20to=20ops/t?= =?UTF-8?q?ouch=20=E2=80=94=20admin/=20is=20reserved=20by=20Functions=20ru?= =?UTF-8?q?ntime?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Azure Functions runtime reserves the /admin/ route prefix for its own host APIs, causing our admin/touch route to 404. Moved to ops/touch and switched to AuthorizationLevel.Function. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/DevBrain.Functions/Tools/AdminFunctions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DevBrain.Functions/Tools/AdminFunctions.cs b/src/DevBrain.Functions/Tools/AdminFunctions.cs index 1b4912f..97fd473 100644 --- a/src/DevBrain.Functions/Tools/AdminFunctions.cs +++ b/src/DevBrain.Functions/Tools/AdminFunctions.cs @@ -25,7 +25,7 @@ public AdminFunctions(IDocumentStore store) /// [Function(nameof(TouchAllDocuments))] public async Task TouchAllDocuments( - [HttpTrigger(AuthorizationLevel.Admin, "post", Route = "admin/touch")] HttpRequestData req) + [HttpTrigger(AuthorizationLevel.Function, "post", Route = "ops/touch")] HttpRequestData req) { var touched = await _store.TouchAllAsync(); From 54cbb91b41d38a645bf9f22d9bb3e94da525509d Mon Sep 17 00:00:00 2001 From: Derek Gabriel Date: Sun, 12 Apr 2026 17:45:23 -1000 Subject: [PATCH 2/2] docs: add metadata/compare tools to ref:devbrain-usage seed doc Documents GetDocumentMetadata, CompareDocument, and the recommended sync workflow for checking before writing. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/seed/ref-devbrain-usage.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/docs/seed/ref-devbrain-usage.md b/docs/seed/ref-devbrain-usage.md index 171bf7b..ec9e8ea 100644 --- a/docs/seed/ref-devbrain-usage.md +++ b/docs/seed/ref-devbrain-usage.md @@ -41,6 +41,33 @@ GetDocument(key: "state:current", project: "devbrain") SearchDocuments(query: "durable functions", project: "devbrain") ``` +## Checking Before Writing — Metadata and Compare + +Before importing or syncing a document, check whether the stored version is already up to date. This avoids unnecessary writes and wasted tokens. + +### Quick existence and size check +``` +GetDocumentMetadata(key: "sprint:license-sync", project: "devbrain") +``` +Returns key, project, tags, updatedAt, updatedBy, contentHash (SHA-256), and contentLength (character count) — **without** the content body. Use this to: +- Check if a document exists +- See when it was last updated and by whom +- Compare content length against your candidate as a fast "obviously different" check + +### Confirm content matches before skipping a write +``` +CompareDocument(key: "sprint:license-sync", content: "...candidate text...", project: "devbrain") +``` +Returns `{ found, match, storedContentHash, candidateHash, ... }`. The server hashes the candidate content and compares against the stored hash. You can also pass a precomputed `contentHash` instead of raw content. + +### Recommended sync workflow +1. Call `GetDocumentMetadata` — if not found, upsert immediately +2. If found, compare `contentLength` against your candidate's character count — if obviously different, upsert +3. If lengths match, call `CompareDocument` with the candidate content — if `match: true`, skip the write +4. If `match: false`, upsert + +This pattern avoids pulling the full stored document into context just to decide whether to write. + ## Key Conventions Keys use **colon** as the separator. Slash-separated keys (`sprint/foo`) still work for backward compatibility, but colons are the canonical, recommended convention — they signal "DevBrain key" at a glance and avoid being confused with file paths.