Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
929f0fd
style(search): strip trailing whitespace in graph_adapter
Sep 22, 2026
f0cd354
fix(release): align version to 3.5.0 in extension.toml and __init__
Sep 22, 2026
34fe6e7
docs: sync version references to 3.5.0
Sep 22, 2026
e65748a
test(e17): add signal-value experiment harness
Sep 22, 2026
b17d41a
test(e17): validate TESTS-signal as a verifier via mutation testing
Sep 22, 2026
0aa72c3
test(e17): profile verification strength across multiple mutations
Sep 22, 2026
cbbafa1
test(e17): scale strength profiling; AST proxies do not predict kill-…
Sep 22, 2026
bcc056c
docs(known-issues): archive autosynced experiment entries
Sep 22, 2026
00ec5a6
fix(search): revive idle embedder, unblock hot-reload in search
Sep 22, 2026
8dc7593
docs(experiments): record E6 commit-gate and E7 symptom-index eval
Sep 22, 2026
03516b2
docs(experiments): finalize E7 eval (3 models, arrival-symptom NONE 1…
Sep 22, 2026
4b4739f
feat(graph): add quiet-break isolation gate (delta A+B)
Sep 22, 2026
a250979
feat(cli): redact credentials at delivery boundary
Sep 22, 2026
c2f4a4c
feat(delivery): add anti-numbing restraint for advisory notes
Sep 22, 2026
44d451f
docs(experiments): record E11 frozen list vs new arrival index
Sep 22, 2026
837f457
docs: clean-state verification 44d451f6 (1800 passed, all gates green)
Sep 22, 2026
808864c
test(graph): make TESTS-signal fixture platform-independent
Sep 23, 2026
8bcebf8
docs: record CI green on PR #40 (ubuntu+windows+clean-state)
Sep 23, 2026
5aebd3d
feat(opencode): add commit-time gate hook (stale block + isolation ad…
Sep 23, 2026
7a85543
fix(opencode): invoke CLI via node:child_process, not plugin context
Sep 23, 2026
fb50481
docs: record opencode gate hook live verification
Sep 23, 2026
d502441
fix(docs): verify_references no longer crashes on a lone dollar in b…
Sep 23, 2026
5aaf9b5
feat(docs): deterministic L1 doc-reference checker (near-zero FP)
Sep 23, 2026
db5e80f
docs(experiments): record E13 test-time measurement (xdist ~15%)
Sep 24, 2026
a9f87d2
docs: sync tool counts to code (65 = 32 core + 16 intel + 13 inline …
Sep 24, 2026
3c1f507
docs(readme): semantic audit fixes against code
Sep 24, 2026
34c39d2
docs(agents): semantic audit fixes against code
Sep 24, 2026
ce43110
docs+fix: resolve "not registered" tools; correct server_tools log c…
Sep 24, 2026
6bfc379
docs(architecture): semantic audit fixes (en/ru/zh) against code
Sep 24, 2026
016736a
docs(architecture): fix services/labels/tool-group counts against code
Sep 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -225,3 +225,7 @@ test_result.txt
_mcp_reindex_client.py
_measure_*.py
.red_team_state.md

# E17 experiment: regenerable prompt shards (rebuild via e17_export_*.py)
experiments/bootstrap/e17_shards/*.txt
experiments/bootstrap/e17_judge/*.txt
130 changes: 130 additions & 0 deletions .opencode/plugin/mscodebase_gate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// mscodebase_gate.ts — opencode-хук: детерминированные заметки MSCodeBase в момент действия.
//
// Два гейта на `git commit` (мост: `python -m src.cli <tool> <json>`, cwd=проект; CLI --project игнорирует):
// 1. stale_detector — BLOCK при дрейфе версий (доказан в E6: модель отказ не обходит).
// 2. graph_query isolation — ADVISORY: «тихий слом» графа (осиротение узла). Soft: у гейта есть FP.
//
// Advisory реализован через before+after: pre-commit diff считается в `before` и кладётся в stash по
// callID; текст дописывается в результат в `after` (не блокирует). Блокирующий режим — только stale
// (объективный) и явный MSCODEBASE_ISOLATION_GATE=block.
//
// Переключатели (env): MSCODEBASE_PY, MSCODEBASE_STALE_GATE=block|off,
// MSCODEBASE_ISOLATION_GATE=advisory|block|off, MSCODEBASE_GATE_LOG.
// Хук никогда не роняет хост: любые сбои → лог, без throw (кроме намеренного блока).
//
// ВАЖНО: вызов python — через node:child_process, НЕ через `$` из контекста плагина: в opencode
// 1.18.23 контекст фабрики не содержит `$` (API дрейфанул) → `TypeError: $ is not a function`.

import type { Plugin } from "@opencode-ai/plugin"
import { appendFileSync, mkdirSync } from "node:fs"
import { execFile } from "node:child_process"
import { dirname } from "node:path"

const PY = process.env.MSCODEBASE_PY ?? "D:/Project/MSCodeBase/venv/Scripts/python.exe"
const LOG = process.env.MSCODEBASE_GATE_LOG ?? "C:/Users/misha/AppData/Local/Temp/opencode/mscodebase_gate.log"
const STALE_MODE = process.env.MSCODEBASE_STALE_GATE ?? "block"
const ISO_MODE = process.env.MSCODEBASE_ISOLATION_GATE ?? "advisory"

const STALE_ARGS = "{}"
const ISO_ARGS = '{"action":"isolation","kwargs":{"restraint":true}}'

function log(rec: Record<string, unknown>) {
try {
mkdirSync(dirname(LOG), { recursive: true })
appendFileSync(LOG, JSON.stringify({ t: Date.now(), ...rec }) + "\n")
} catch {
// never break the host
}
}

function cli(directory: string, tool: string, argsJson: string): Promise<string> {
return new Promise((resolve) => {
try {
execFile(
PY,
["-m", "src.cli", tool, argsJson],
{ cwd: directory, timeout: 90000, windowsHide: true, maxBuffer: 4 * 1024 * 1024 },
(_err, stdout) => resolve(stdout ?? ""),
)
} catch (e) {
log({ kind: "cli_spawn_error", err: String(e).slice(0, 200) })
resolve("")
}
})
}

function staleDrift(out: string): number {
const m = /Total drift instances:\s*(\d+)/i.exec(out)
return m ? parseInt(m[1], 10) : 0
}

function isolationCount(out: string): number {
const r = /removed_last_caller:\s*(\d+)/i.exec(out)
const n = /new_orphan:\s*(\d+)/i.exec(out)
return (r ? parseInt(r[1], 10) : 0) + (n ? parseInt(n[1], 10) : 0)
}

function isolationSuppressed(out: string): boolean {
return /deliver:\s*✗/i.test(out) || /deliver:\s*false/i.test(out)
}

const stash = new Map<string, string>()

export default (async ({ directory }) => {
log({ kind: "init", directory, stale: STALE_MODE, isolation: ISO_MODE })
return {
"tool.execute.before": async (input: any, output: any) => {
if (input.tool !== "bash") return
const cmd = String(output.args?.command ?? "")
if (!/\bgit\s+commit\b/.test(cmd)) return

// ── Gate 1: stale_detector (block) ──
if (STALE_MODE !== "off") {
try {
const out = await cli(directory, "stale_detector", STALE_ARGS)
const drift = staleDrift(out)
log({ kind: "stale", drift, out: out.slice(0, 400) })
if (STALE_MODE === "block" && drift > 0) {
log({ kind: "stale_block", drift })
throw new Error(
`CRYSTAL-GATE: ${drift} doc-drift instance(s). Docs assert a version the code no longer is.\n${out.slice(0, 500)}`,
)
}
} catch (e) {
if (String(e).includes("CRYSTAL-GATE")) throw e
log({ kind: "stale_error", err: String(e).slice(0, 200) })
}
}

// ── Gate 2: graph isolation (advisory/block) ──
if (ISO_MODE !== "off") {
try {
const out = await cli(directory, "graph_query", ISO_ARGS)
const count = isolationCount(out)
log({ kind: "isolation", count, out: out.slice(0, 400) })
if (count > 0) {
if (ISO_MODE === "block") {
log({ kind: "isolation_block", count })
throw new Error(`GRAPH-GATE (block): this commit isolates ${count} graph node(s).\n${out.slice(0, 500)}`)
}
if (!isolationSuppressed(out)) stash.set(input.callID, out)
}
} catch (e) {
if (String(e).includes("GRAPH-GATE")) throw e
log({ kind: "isolation_error", err: String(e).slice(0, 200) })
}
}
},

"tool.execute.after": async (input: any, output: any) => {
if (ISO_MODE !== "advisory") return
const cached = stash.get(input.callID)
if (!cached) return
stash.delete(input.callID)
log({ kind: "isolation_advisory", len: cached.length })
output.output =
(output.output ?? "") +
`\n\n✦ GRAPH-GATE (advisory): this commit isolates graph node(s).\n${cached.slice(0, 500)}`
},
}
}) satisfies Plugin
18 changes: 9 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Raw Input: {}
| 3 | `intel_get_project_memory` | `{}` |
| 4 | `intel_explain_project_state` | `{}` |

5. **Источник правды:** `src/mcp/server.py` + `src/core/intelligence_layer.py`.
5. **Источник правды:** `src/mcp/server.py` + `src/core/intelligence/layer.py`.
6. **После ошибки** — не retry с теми же JSON. Сначала `debug_runtime_passport` `{}`, потом альтернатива.

**Reindex (Raw Input):**
Expand Down Expand Up @@ -302,7 +302,7 @@ intel_get_project_memory ──> codebase(action="git", path="log") / cod
intel_get_project_context ──> (aggregates 5+ calls)
```

## 2. AVAILABLE TOOLS (64)
## 2. AVAILABLE TOOLS (65)

> **Полный справочник** (аргументы, когда вызывать, anti-patterns):
> источник правды — `src/mcp/server_tools.py` + `src/mcp/tools/` + `src/core/intelligence/tools_reg.py`.
Expand All @@ -319,7 +319,7 @@ intel_get_project_context ──> (aggregates 5+ calls)

Inline/Diagnostic (13): `debug_runtime_passport`, `intel_get_project_context`, `intel_explain_project_state`, `get_runtime_counters`, `intel_tool_health`, `intel_execution_timeline`, `refresh_db_connection`, `notify_change`, `read_live_file`, `get_logs`, `get_health_report`, `dual_arm_health_check`, `ack_impact`.

### B. Core MCP & Search (31 tools)
### B. Core MCP & Search (32 tools)

<!-- stale-ignore -->
> **v3.2.0 Data Flow:** PropertyGraph содержит `ASSIGNED_FROM`-рёбра, отслеживающие
Expand All @@ -339,14 +339,14 @@ Inline/Diagnostic (13): `debug_runtime_passport`, `intel_get_project_context`, `
`graph_query(action=query|cypher|related|flow)`,
`submit_background_task`, `stale_detector`.

> **Not registered (consolidated):** the 14 names below are documented in older
> revisions but are **NOT exposed as MCP tools** in the current build — their
> functionality is covered by `search_code`, `get_symbol_info`, `impact_analysis`,
> and the `intel_*` suite. Do not call them; they return `tool not found`.
> **Hidden core tools (default allowlist):** core tool classes that are not in the
> default `MSCODEBASE_MCP_TOOLS` allowlist are **not exposed** to the MCP client
> (calling them returns `tool not found`) until added to the allowlist. Examples:
> `get_repo_map`, `get_repo_rank`, `get_hotspots`, `get_bug_correlation`,
> `detect_communities`, `cross_repo_search`, `cross_project_deps`,
> `find_duplicates`, `generate_chunk_summaries`, `scan_changes`,
> `find_similar_bugs`, `get_context`, `verify_action`, `get_task_status`.
> `find_similar_bugs`, `get_context`, `bootstrap_pipeline`.
> (Intel / inline / dev tools are always registered and visible.)

> Hub-маршруты `codebase(action=...)` (не отдельные MCP-тулы):
> `codebase(action="index", path=status|progress|health|timeline|project_dir)` — индекс;
Expand Down Expand Up @@ -449,7 +449,7 @@ For file renames, use `apply_file_move(old, new)` instead of `notify_change` —
7. Did I check `diagnostics`?
8. Did I run `python -m pytest tests/ -k write_tools -v` before committing?
9. **CI проверен через `gh run view --log-failed`** (последний ран — механический guard против «CI green» на словах):
- Перед push: последний ран не красный. После push: новый ран зелёный на ВСЕХ джобах — ubuntu matrix (3.10-3.12) + windows; локальный Windows-прогон слеп к POSIX-фейлам (WISDOM 2026-08-08).
- Перед push: последний ран не красный. После push: новый ран зелёный на ВСЕХ джобах — ubuntu + windows (Python 3.14); локальный Windows-прогон слеп к POSIX-фейлам (WISDOM 2026-08-08).
- Точные фейлы даёт `gh run view --log-failed` — аннотации GitHub показывают только «exit code 1».
10. **`bash scripts/verify_clean_state.sh` — проверка с чистого состояния (clone + venv + install + tests)**
- Вывод должен содержать: `CLEAN STATE VERIFICATION: PASSED`
Expand Down
Loading
Loading