capture #49b: CaptureService use-case + BrainStore extraction + ports/entities #51
Closed
opened 2026-06-22 20:26:55 +00:00 by mathias
·
1 comment
No Branch/Tag Specified
main
fix/pipeline-writes-158
fix/edit-path-io-192
fix/create-regular-188
fix/guard-special-179
fix/linkcheck-keeps-write-178
fix/write-dir-redirect-173
fix/tunnel-detect-174
fix/pipeline-root-157
w3/154-mcp-auth-wiring
fix/tunnel-traversal
test/in-brain-targets-171
fix/brain-scan-root-157
fix/graph-wiki-root-157
fix/vectorstore-root-157
fix/notes-root-157
fix/search-root-157
fix/brainwide-root-157
fix/raw-symlinks-153
feat/symlink-tripwire-157
fix/rest-auth-149
fix/123-brain-edit-envelope-check
feat/106-page-aware-extraction
fix/105-source-drift-on-main
fix/104-surface-merge-conflicts-on-main
agent/b1-compile-on-ingest
agent/104-surface-merge-conflicts
agent/105-source-drift
agent/107-loud-unconfigured-alerting
feat/brain-read-edit
fix/capture-i1-refusal-names-target
renovate/configure
feat/consolidate-single-harness
icebox/cmd-routing
feat/brain-pending-promote
fix/close-session-classification-refresh
fix/capture-summarywriter
v0.24.0
v0.23.1
v0.23.0
v0.22.0
v0.21.1
v0.21.0
v0.20.1
v0.20.0
v0.19.1
v0.19.0
v0.18.4
v0.18.3
v0.18.2
v0.18.1
v0.18.0
v0.17.0
v0.16.1
v0.16.0
v0.15.0
v0.14.0
v0.13.2
v0.13.1
v0.13.0
v0.12.1
v0.12.0
v0.11.2
icebox/cmd-routing-2026-07-01
v0.11.1
v0.11.0
v0.10.0
v0.9.0
v0.8.0
v0.7.0
v0.6.0
v0.5.0
v0.4.1
v0.4.0
v0.3.0
v0.2.0
v0.1.0
Labels
Clear labels
agent/ready
blocked/client
blocked/supplier
blocked/upstream
risk/high
risk/low
risk/medium
size/l
size/m
size/s
size/xs
status:dispatch
status:dispatched
status:review
status:reviewing
type/chore
type/decision
type/docs
type/feat
type/fix
type/ops
type/research
type/test
Meets the agent-ready contract; authorizes unattended execution
Waiting on the client
Waiting on a supplier
Waiting on an upstream project or vendor
Irreversible, security-relevant, or control plane
Reversible, local, test-covered
Touches shared state, deploys or data
Too big - split it
Under two days
Under half a day
Under an hour
Maintenance, no behaviour change
Human decision required; never agent/ready
Documentation only
New capability
Corrects broken behaviour
Infrastructure, deploy, runtime
Investigate; output is a finding, not code
Test coverage only
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: mathias/hyperguild#51
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Parent: #49 · Spec:
specs/capture-bdd-spec.md§1 · Depends on: nothing (buildable against fake ports) · Blocks: #49c, #49dScope
The Clean-Architecture core of capture: extract #45's brain write/update/get logic out of the MCP-only layer into a shared
BrainStore, define the ports and entities, and implement theCaptureServiceorchestration. Build and unit-test against fake ports — no live gating, no HTTP, no real gitea yet. The classification check is an injected policy (satisfied later by #49a/#50).This is the biggest single chunk and the spine everything else hangs off.
Ground-truth (from #49)
brain_update/brain_getcurrently live iningestion/internal/mcp/only;/write(api.WriteNote, a free function) is the only brain write reachable from the REST/api layer. The extraction lifts the update/get logic into a shared impl both the MCP handlers and capture call — the Clean-Arch payoff, real work, not a wrapper.What to build
ingestion/internal/capture/package.BrainStore—Write(ctx, note) (ref, error),Update(ctx, slug, note) (ref, error),Get(ctx, id) (note, error)whereref = {id, path, content_hash}.IssueTracker—CreateIssue,CloseIssue,CommentIssue(interface only here; impl in #49c).SummaryWriter—WriteFile(repo, path, content) error.ClassificationPolicy—Derive(target) level+Effective(declared, derived) level(interface only; impl in #49a/#50).AuditSink—Record(ctx, auditEntry) error(interface only; impl in #49e/#49f).Insight,Ticket,Summary,CaptureContext,CaptureReceipt— plain structs.BrainStoreextraction: liftbrain_update/brain_get/brain_writelogic frommcp/into a concreteBrainStoreimpl; re-point the existing MCP handlers at it so there's one implementation, not two (DRY — the whole point). Preserve the #45 read-after-write contract and the batch staleness discipline inside the store/use-case so callers never carry the rule.CaptureService.Capture(ctx, CaptureInput) (CaptureReceipt, error): validate-before-write (fail-closed), resolve effective classification via the policy port, orchestrate insights (write/supersede) → tickets → summary, best-effort with per-item outcome, assemble the partial-aware receipt.dry_runshort-circuits after validation.Acceptance criteria
capture/package: ports, entities,CaptureServiceBrainStoreconcrete impl with Write/Update/Get; MCP handlers re-pointed at it (no duplicate logic)ok/error; no rollbackdry_runreturns would-be receipt, writes nothingClassificationPolicy(stricter wins)brain_update/brain_gettests still pass after re-pointingtask checkgreenNotes
No HTTP, no live gitea, no live audit in this issue — all injected as interfaces, real impls land in #49c/d/e/f. The value here is a fully unit-tested use-case before any I/O is wired. Gherkin scenarios this satisfies (against fakes): supersede-not-duplicate, fail-closed validation, partial-failure receipt, dry-run, stricter-classification-wins.
Implemented — PR #57 (open, stacked on #56)
PR: #57 · base
feat/capture-classification(merge #56 first; #57 is #51-only diff)Two packages:
capture/— pure use-case: ports (BrainStore/IssueTracker/SummaryWriter/ClassificationPolicy/AuditSink), entities,CaptureService.Capture(validate-fail-closed → effective classification → insights/tickets/summary best-effort → audit → partial receipt;dry_runwrites nothing).brainstore/— the extraction: one concreteStoreimplementingcapture.BrainStore(api primitives + wing-index/auto-tunnel/graph). MCPbrain_write/brain_update/brain_getre-pointed at it — one impl, not two. Existing MCP tests pass unmodified;{id,path,content_hash}contract preserved.Soft dep on #50: reuses
classification.Level/Targetrather than duplicating the enum → branch stacked on #56.classification.Configis a drop-inClassificationPolicy.Deliberate scope boundaries:
Effectivefolded into the service asStricter(port staysDerive-only).All ACs met;
task checkgreen. BDD scenarios satisfied against fakes: supersede-not-duplicate, fail-closed validation, partial-failure receipt, dry-run, stricter-wins, caller-raising-honoured, summary fidelity.Critical path next: #52 (Gitea
IssueTrackerimpl — depends on this) → #53 (REST + I1 gate). TheIssueTracker/SummaryWriter/AuditSinkports are ready for their real adapters.