coverage~bigbes/sr-ht-spec3cb1c03dmcpsrv/read.go

Coverage
95.2% 20/21 statements
Δ
Blob
9ee708d
Uncovered L79-L86
1 package mcpsrv
2
3 import (
4 "context"
5 "fmt"
6
7 "sourcecraft.dev/bigbes/sr-ht-spec/service"
8 )
9
10 type readInput struct {
11 Space string `json:"space" jsonschema:"the space to read from, written \"~owner/name\" as spec_list and spec_search report it"`
12 Document string `json:"document" jsonschema:"which document: its frontmatter id (\"SPEC-0007\"), or its path with or without the \".md\" extension (\"specs/0007-storage\")"`
13 Rev string `json:"rev,omitempty" jsonschema:"pin the read to one immutable revision, given as a git object name (lowercase hex, as returned in the rev field of any result). Omit this to read the space's approved head, which is what an agent almost always wants: the reviewed text. Branch names are not accepted."`
14 }
15
16 type readOutput struct {
17 Space string `json:"space"`
18 // ID is how this document is addressed: its frontmatter id when that is
19 // well-formed and unique in the space, otherwise its path without the
20 // extension.
21 ID string `json:"id"`
22 // DocID is the frontmatter id when the document has a well-formed one, and
23 // empty otherwise. It differs from ID exactly when the document has no
24 // usable id, which is the case an agent proposing an edit needs to see.
25 DocID string `json:"doc_id,omitempty"`
26 Path string `json:"path"`
27 // Rev is the commit this content was read at. It is immutable: pass it back
28 // as the rev argument to re-read these exact bytes. It is also the value
29 // the Phase 3 write plane takes as If-Match when it is an approved head.
30 Rev string `json:"rev"`
31 // Blob is the sha of this document's content, and changes only when the
32 // content does.
33 Blob string `json:"blob"`
34 // Pinned reports how Rev was chosen. False means the caller named no
35 // revision and this is the space's approved head as of this call — the
36 // reviewed, canonical text. True means the caller pinned a revision, and
37 // whether that revision is on the approved branch is the caller's business:
38 // this service does not claim it either way.
39 Pinned bool `json:"pinned"`
40 Title string `json:"title,omitempty"`
41 Section string `json:"section,omitempty"`
42 // Status is the document's authored lifecycle marker (draft, review,
43 // superseded). It is not approval state: a document is approved by being
44 // reachable from the approved ref, never by its frontmatter.
45 Status string `json:"status,omitempty"`
46 Summary string `json:"summary,omitempty"`
47 Tags []string `json:"tags,omitempty"`
48 // Markdown is the whole document, frontmatter included, exactly as stored.
49 // It is the text to edit and send back when proposing a change.
50 Markdown string `json:"markdown"`
51 }
52
53 25 func readHandler(ctx context.Context, b Backend, in readInput) (readOutput, error) {
54 25 if err := requireRead(ctx); err != nil {
55 1 return readOutput{}, err
56 1 }
57 24 ref, err := parseSpace(in.Space)
58 24 if err != nil {
59 1 return readOutput{}, err
60 1 }
61 23 rev, err := parseRev(in.Rev)
62 23 if err != nil {
63 4 return readOutput{}, err
64 4 }
65 19 sp, err := b.Docs.OpenSpace(ctx, ref)
66 19 if err != nil {
67 2 return readOutput{}, missingOrDenied(err, "spec_read", noSpace(ref))
68 2 }
69 17 arc, bodies, resolved, err := archiveAt(ctx, b, sp, rev)
70 17 if err != nil {
71 2 return readOutput{}, missingOrDenied(err, "spec_read", noRevision(ref, rev))
72 2 }
73 15 page, err := resolvePage(arc, in.Document)
74 15 if err != nil {
75 3 return readOutput{}, err
76 3 }
77 12 body, ok := bodies[page.Path]
78 12 if !ok {
79 0 // The archive is built from these very bodies, so a page without one
80 0 // is a broken invariant rather than a missing document — this service's
81 0 // fault and not an answer about the corpus, so it goes to the agent as a
82 0 // protocol error and the detail goes to the log. Returning an empty
83 0 // markdown field would be indistinguishable from an empty document.
84 0 return readOutput{}, internalError(
85 0 fmt.Errorf("document %s at %s in %s has no body", page.Path, resolved, ref), "spec_read")
86 0 }
87 12 return readOutput{
88 12 Space: ref.String(),
89 12 ID: page.ID,
90 12 DocID: page.DocID,
91 12 Path: page.Path,
92 12 Rev: resolved,
93 12 Blob: page.Blob,
94 12 Pinned: rev != service.ApprovedRev,
95 12 Title: page.Title,
96 12 Section: page.Section,
97 12 Status: string(page.Status),
98 12 Summary: page.Summary,
99 12 Tags: page.Tags,
100 12 Markdown: string(body),
101 12 }, nil
102 }