Compare commits
base: mathias/hyperguild:v0.14.0
mathias/hyperguild:main
mathias/hyperguild:fix/pipeline-writes-158
mathias/hyperguild:fix/edit-path-io-192
mathias/hyperguild:fix/create-regular-188
mathias/hyperguild:fix/guard-special-179
mathias/hyperguild:fix/linkcheck-keeps-write-178
mathias/hyperguild:fix/write-dir-redirect-173
mathias/hyperguild:fix/tunnel-detect-174
mathias/hyperguild:fix/pipeline-root-157
mathias/hyperguild:w3/154-mcp-auth-wiring
mathias/hyperguild:fix/tunnel-traversal
mathias/hyperguild:test/in-brain-targets-171
mathias/hyperguild:fix/brain-scan-root-157
mathias/hyperguild:fix/graph-wiki-root-157
mathias/hyperguild:fix/vectorstore-root-157
mathias/hyperguild:fix/notes-root-157
mathias/hyperguild:fix/search-root-157
mathias/hyperguild:fix/brainwide-root-157
mathias/hyperguild:fix/raw-symlinks-153
mathias/hyperguild:feat/symlink-tripwire-157
mathias/hyperguild:fix/rest-auth-149
mathias/hyperguild:fix/123-brain-edit-envelope-check
mathias/hyperguild:feat/106-page-aware-extraction
mathias/hyperguild:fix/105-source-drift-on-main
mathias/hyperguild:fix/104-surface-merge-conflicts-on-main
mathias/hyperguild:agent/b1-compile-on-ingest
mathias/hyperguild:agent/104-surface-merge-conflicts
mathias/hyperguild:agent/105-source-drift
mathias/hyperguild:agent/107-loud-unconfigured-alerting
mathias/hyperguild:feat/brain-read-edit
mathias/hyperguild:fix/capture-i1-refusal-names-target
mathias/hyperguild:renovate/configure
mathias/hyperguild:feat/consolidate-single-harness
mathias/hyperguild:icebox/cmd-routing
mathias/hyperguild:feat/brain-pending-promote
mathias/hyperguild:fix/close-session-classification-refresh
mathias/hyperguild:fix/capture-summarywriter
mathias/hyperguild:v0.24.0
mathias/hyperguild:v0.23.1
mathias/hyperguild:v0.23.0
mathias/hyperguild:v0.22.0
mathias/hyperguild:v0.21.1
mathias/hyperguild:v0.21.0
mathias/hyperguild:v0.20.1
mathias/hyperguild:v0.20.0
mathias/hyperguild:v0.19.1
mathias/hyperguild:v0.19.0
mathias/hyperguild:v0.18.4
mathias/hyperguild:v0.18.3
mathias/hyperguild:v0.18.2
mathias/hyperguild:v0.18.1
mathias/hyperguild:v0.18.0
mathias/hyperguild:v0.17.0
mathias/hyperguild:v0.16.1
mathias/hyperguild:v0.16.0
mathias/hyperguild:v0.15.0
mathias/hyperguild:v0.14.0
mathias/hyperguild:v0.13.2
mathias/hyperguild:v0.13.1
mathias/hyperguild:v0.13.0
mathias/hyperguild:v0.12.1
mathias/hyperguild:v0.12.0
mathias/hyperguild:v0.11.2
mathias/hyperguild:icebox/cmd-routing-2026-07-01
mathias/hyperguild:v0.11.1
mathias/hyperguild:v0.11.0
mathias/hyperguild:v0.10.0
mathias/hyperguild:v0.9.0
mathias/hyperguild:v0.8.0
mathias/hyperguild:v0.7.0
mathias/hyperguild:v0.6.0
mathias/hyperguild:v0.5.0
mathias/hyperguild:v0.4.1
mathias/hyperguild:v0.4.0
mathias/hyperguild:v0.3.0
mathias/hyperguild:v0.2.0
mathias/hyperguild:v0.1.0
..
compare: mathias/hyperguild:feat/brain-read-edit
mathias/hyperguild:main
mathias/hyperguild:fix/pipeline-writes-158
mathias/hyperguild:fix/edit-path-io-192
mathias/hyperguild:fix/create-regular-188
mathias/hyperguild:fix/guard-special-179
mathias/hyperguild:fix/linkcheck-keeps-write-178
mathias/hyperguild:fix/write-dir-redirect-173
mathias/hyperguild:fix/tunnel-detect-174
mathias/hyperguild:fix/pipeline-root-157
mathias/hyperguild:w3/154-mcp-auth-wiring
mathias/hyperguild:fix/tunnel-traversal
mathias/hyperguild:test/in-brain-targets-171
mathias/hyperguild:fix/brain-scan-root-157
mathias/hyperguild:fix/graph-wiki-root-157
mathias/hyperguild:fix/vectorstore-root-157
mathias/hyperguild:fix/notes-root-157
mathias/hyperguild:fix/search-root-157
mathias/hyperguild:fix/brainwide-root-157
mathias/hyperguild:fix/raw-symlinks-153
mathias/hyperguild:feat/symlink-tripwire-157
mathias/hyperguild:fix/rest-auth-149
mathias/hyperguild:fix/123-brain-edit-envelope-check
mathias/hyperguild:feat/106-page-aware-extraction
mathias/hyperguild:fix/105-source-drift-on-main
mathias/hyperguild:fix/104-surface-merge-conflicts-on-main
mathias/hyperguild:agent/b1-compile-on-ingest
mathias/hyperguild:agent/104-surface-merge-conflicts
mathias/hyperguild:agent/105-source-drift
mathias/hyperguild:agent/107-loud-unconfigured-alerting
mathias/hyperguild:feat/brain-read-edit
mathias/hyperguild:fix/capture-i1-refusal-names-target
mathias/hyperguild:renovate/configure
mathias/hyperguild:feat/consolidate-single-harness
mathias/hyperguild:icebox/cmd-routing
mathias/hyperguild:feat/brain-pending-promote
mathias/hyperguild:fix/close-session-classification-refresh
mathias/hyperguild:fix/capture-summarywriter
mathias/hyperguild:v0.24.0
mathias/hyperguild:v0.23.1
mathias/hyperguild:v0.23.0
mathias/hyperguild:v0.22.0
mathias/hyperguild:v0.21.1
mathias/hyperguild:v0.21.0
mathias/hyperguild:v0.20.1
mathias/hyperguild:v0.20.0
mathias/hyperguild:v0.19.1
mathias/hyperguild:v0.19.0
mathias/hyperguild:v0.18.4
mathias/hyperguild:v0.18.3
mathias/hyperguild:v0.18.2
mathias/hyperguild:v0.18.1
mathias/hyperguild:v0.18.0
mathias/hyperguild:v0.17.0
mathias/hyperguild:v0.16.1
mathias/hyperguild:v0.16.0
mathias/hyperguild:v0.15.0
mathias/hyperguild:v0.14.0
mathias/hyperguild:v0.13.2
mathias/hyperguild:v0.13.1
mathias/hyperguild:v0.13.0
mathias/hyperguild:v0.12.1
mathias/hyperguild:v0.12.0
mathias/hyperguild:v0.11.2
mathias/hyperguild:icebox/cmd-routing-2026-07-01
mathias/hyperguild:v0.11.1
mathias/hyperguild:v0.11.0
mathias/hyperguild:v0.10.0
mathias/hyperguild:v0.9.0
mathias/hyperguild:v0.8.0
mathias/hyperguild:v0.7.0
mathias/hyperguild:v0.6.0
mathias/hyperguild:v0.5.0
mathias/hyperguild:v0.4.1
mathias/hyperguild:v0.4.0
mathias/hyperguild:v0.3.0
mathias/hyperguild:v0.2.0
mathias/hyperguild:v0.1.0
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
36b757fabf |
feat(mcp): add brain_read + brain_edit, contained to the sync source (brain#4)
brain_read returns a note verbatim; brain_edit is str_replace with an exactly-once match. Both operate on INGEST_BRAIN_DIR, which is the pod's mount of /var/lib/supervisor/brain — the tree brain-sync commits from, so an edit reaches gitea on the next cycle rather than landing somewhere the sync cannot see it (brain#2). An adversarial design review before implementation changed three things, each of which would otherwise have shipped: 1. Governance files are NOT in the model-facing tool. The original plan allowed root *.md so CLAUDE.md had an MCP path at all — the absence of one is what pushed a session to edit via the gitea REST API on 2026-06-16 and wedge the sync. But brain content is ingested from the outside world, reaches a model's context via brain_query, and that model would hold the editor: one poisoned page could rewrite the CLAUDE.md a .dispatch-allow agent later loads as instructions. Worse, brain-sync merges with --strategy-option=ours, so the live tree wins against a human's corrective push on exactly the conflicting lines. CLAUDE.md now goes through brain_edit_root: de-surfaced from tools/list (the brain_index precedent, ADR-0012 rule 4) and gated on the local static principal, so a claude.ai-origin session is refused. The two scopes are disjoint — the privileged door has the smaller reach. 2. Reads needed the same allowlist, and brain_get already lacked it. api.ReadNote resolves any brain-relative path and parseFrontmatter returns the whole file when there is no fence, so brain_get reads verbatim session transcripts under archive/ (up to 500 KB, never BM25-indexed, so nobody thinks of them as reachable). A test proves the exposure was live; the same Resolve now gates brain_get. 3. Canonicalise before allowlisting. A prefix check on the raw argument accepts knowledge/../.git/hooks/post-commit, which Clean collapses to a git hook that brain-sync executes inside a pod holding the Gitea push credentials. Traversal, symlink escape, dotfiles, .git/, archive/, sessions/ and raw/ are refused by a static backstop that does not depend on the allowlist being right. There were no traversal tests in this repo before. Also from the review: overlapping match counting (bytes.Count says "aa" occurs once in "aaa", so a Count-based uniqueness check accepts an ambiguous edit); UTF-8 validation on both sides, because encoding/json substitutes U+FFFD and would hand back bytes the file does not contain, making every derived old_str unmatchable; refusal while .git/MERGE_HEAD or index.lock exists, since an edit racing brain-sync's merge is either hard-reset away or committed as a wrongly resolved conflict; flock plus a per-path mutex with the read taken inside the lock, because two pods share the hostPath during a RollingUpdate and uniqueness evaluated against a stale read loses an update while reporting success; same-dir *.tmp + rename + chmod 0644 + fsync of file and parent; and reindex only when the edit touches frontmatter, since BM25 walks live and embeddings are mtime-driven. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BeAp5LTscnz2W7Ubt4eJ6m |
||
|
|
db00644cab |
fix(capture): name what escalated the classification in an I1 refusal (#91)
infra#265 reported "capture with a tickets array fails": 20 tickets
errored, 5 errored, the caller fell back to 20 individual issue_create
calls and filed a bug against the array.
The array was never the failing dimension. Every ticket in that batch
targeted a client repo, and the I1 sovereignty gate refuses a
confidential capture through a us-nexus origin at ANY length — reproduced
live today against brain-mcp: length 1 succeeds for an internal repo,
length 20 validates clean, and a single ticket targeting
trucker-ecommerce is refused.
What made it look like an array bug is that the refusal named neither the
offending target nor the fact that a policy said no:
capture refused by I1 sovereignty gate: effective classification
confidential through us-nexus origin
With twenty tickets a caller cannot tell which repo tripped it, so
"the array is broken" is a reasonable conclusion from the evidence
available. resolveClassification now also returns the targets carrying
the effective level, and the refusal names them:
... through us-nexus origin (required by: trucker-ecommerce)
Only targets that actually reach the effective level are named — at
twenty tickets, listing the innocent ones hides the one that matters —
and a caller who declared confidential themselves is told exactly that,
because "you asked for this" and "a repo you touched required it" call
for different fixes.
Regression tests at length 1 and 20 pin the array path that was never
broken, and a third pins per-item partial success: infra#265 asked "if
ticket 3 of 5 fails, what happened to 1 and 2?" — they land, and the
receipt says so per item.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BeAp5LTscnz2W7Ubt4eJ6m
|
1 changed files with 0 additions and 2 deletions
@@ -1,2 +0,0 @@
|
||||
# Presence of this file marks this repo as opt-in for headless dispatch.
|
||||
# See dispatch#3.
|
||||
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.