candor

io.github.tombaldwin由 GitHub 帳號 tombaldwin 發布v0.41.3更新於 Nov 8, 2026

Per-function effect analysis for agents: blast radius, what reaches the network, gate verdicts.

發布方自己的服務:Candor Finance

概覽

AI 產生的概覽

唯讀 MCP 伺服器,依預先算好的 candor 報告回答 TypeScript 專案問題:每個函式的副作用、呼叫圖影響範圍與架構策略判定。

可以做什麼
  • 追蹤呼叫圖影響:反向影響範圍、直接與遞迴呼叫者,以及通往執行某效果函式的最短路徑呼叫鏈
  • 整理效果面:哪些函式直接或繼承地執行 Net、Db、Exec、Fs 等效果,以及程式執行時實際可達什麼
  • 檢視結構:單一函式自身與繼承的效果及字面 hosts、指令、路徑、資料表,以及依模組的效果總覽
  • 檢查策略:假設性修改前的閘門判定、已提交策略的判定、邊界修復建議,以及更新 accept 列的提案
  • 診斷不確定性與漂移:各邊界效果的分散程度、依影響排序的 Unknown 來源,以及相對基線的依函式或供應鏈效果增量
  • 檢視本機活動記錄中量測到的閘門活動
適用情境
當編碼助理需要關於 TypeScript 程式庫執行時效果的確定性答案、而不想手動追蹤呼叫圖時使用:評估一次修改的影響範圍、找出哪些程式會連上網路或資料庫,或判斷修改能否通過儲存庫的架構策略。
執行需求
以 npm 套件 candor-ts 形式在本機透過 stdio 執行,需要 Node.js,僅支援桌面用戶端。必須已有由另外執行的 candor 掃描產生的報告,伺服器本身從不掃描。報告位置來自每次呼叫的 report 前綴、CANDOR_REPORT 環境變數或預設的 .candor/ 目錄;CANDOR_ROOT 可將伺服器鎖定在單一工作區。
安裝前請注意
僅供查詢、唯讀:它讀取報告檔案,不掃描、不修改、不寫入程式碼。答案描述程式「可能到達」什麼,而非「實際做了什麼」,無法解析的呼叫會標為 Unknown 而非純函式,因此乾淨的判定可能並不完整;應檢查 ok 是否存在,而非只看其值。依報告計算的閘門僅供參考,策略或基線無法讀取時會報錯,不會放行。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 candor,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

candor-ts

[Beaky, the candor canary]

candor for TypeScript: per-function side effects, transitively, with a deterministic policy gate. candor-ts resolves every call through the TypeScript compiler API and reports, for each function in your project, which effects it can reach — Net, Fs, Db, Exec, Env, Clock, … — including effects inherited through any chain of calls across files, with a disclosed Unknown wherever resolution fails (a callback value, an any-typed callee — never silently pure). A candor-spec implementation, sibling of the Rust and JVM engines.

Site: candor.poly.io — the measured case in five minutes.

sh
npm install   # typescript + @types/node
node scan.mjs <project-dir>                 # tsconfig.json honored; tests excluded; writes                                            #   <dir>/.candor/report.json + .callgraph.jsonnode scan.mjs . --policy .candor/policy     # the §6.2 gate: exit 1 on violation, 2 if unreadablenode scan.mjs . --gate-json gate.json       # + the structured verdict {spec, ok, violations} (§3.3)CANDOR_BASELINE=saved.json node scan.mjs .  # AS-EFF-005 guard: exit 1 if an existing fn GAINED an                                            #   effect vs the saved report; 2 if it can't evaluate
node scan.mjs --version                     # installed build + spec contract (offline), + upgrade line
node query.mjs show     .candor/report db.save 1   # a function's effects (match ladder)node query.mjs where    .candor/report Net 1       # direct sources vs inheritorsnode query.mjs callers  .candor/report db.save 1   # the blast radius (transitive callers)node query.mjs map      .candor/report 1           # module → effects overviewnode query.mjs containment .candor/report          # §6.1 boundary-effect dispersion (+ baseline = ratchet)node query.mjs blindspots  .candor/report          # the Unknown SOURCES, ranked by blast radiusnode query.mjs whatif   .candor/report db.save Net policy  # pre-edit gate verdict (exit 1)node query.mjs diff     .candor/report baseline 1  # per-function effect delta (exit 1 on a gain;                                                   #   a baseline from a DIFFERENT build ⇒ disclosed ⚠ + exit 0)node query.mjs gate --report dep/.candor/report.json --policy arch.policy --gate-json -                                                   # ⟨0.24⟩ apply a policy to an EXISTING report, NO scan                                                   #   (exit 0/1/2) — the supply-chain verb: gate a                                                   #   DEPENDENCY's published report without its source.                                                   #   Reads that report and nothing else; a rule the wire                                                   #   cannot answer (`forbid`, `allow`, a class-scoped                                                   #   `deny` with the scoping field absent) is REFUSED                                                   #   with exit 2, never evaluated on partial evidence.

A checked-in .candor/config (spec §3.4) replaces the env wiring — policy arch.policy / baseline <report.json> / deps <report paths> one per line, discovered by walking up from the scan target; relative values resolve against the config's repo, so CI is "point at the repo". A configured-but-unusable config/policy/baseline fails loud (exit 2), never silently gateless.

The scan-time baseline guard (AS-EFF-005, spec §7) makes effect regressions un-shippable: point CANDOR_BASELINE (or the config's baseline key) at a saved report, and any function that gained an effect fails the scan — exit 1, the records join the --gate-json verdict, each carrying origin (existing / new / unknown). ⟨0.40⟩ A function ABSENT from the baseline is compared against nothing, so a new effectful function fails too; a new pure one passes, and a new Unknown-only one is named in a note. Module.fn keys mean a renamed file reads as absent: review with candor diff <this run's report> <baseline> before re-recording. The guard is fail-closed like the policy gate: a present-but-unparseable baseline, or one produced by a different engine build (§2.1 — an engine upgrade is baseline-invalidating), exits 2 without evaluating; only a genuinely absent file is a one-line note (guard not active). Keep the two surfaces straight: query diff is the read-only comparison — it discloses a producing-build mismatch (⚠, exit 0) and informs; the scan-time guard is the gate-grade fail-closed surface, the one CI should hold. Semantics mirror the reference engine (candor-java) exactly.

Staying current: check your installed version and upgrade — candor/AGENTS.md §2a. npx -y candor-ts --version prints the build, the spec, and the upgrade one-liner (offline; candor never phones home).

Function names are module-qualified with . segments (src.db.save), so policy scopes read naturally. A function declared inside a TS namespace carries the namespace segments in fn and the callgraph keys (src.util.Ns.helper) — so layer policies on namespaces bite — while the §2 hash join key keeps the bare local name; builds before 0.8.7 omitted the segments, so crossing that line invalidates saved baselines (regenerate them). A pure <scope> rule forbids every effect but not Unknown — the §4 trust marker is uncertainty, not an effect (matching the reference engine, candor-java); deny Unknown <scope> is the explicit knob for boundaries that must also exclude the unverifiable case.

text
# .candor/policydeny Net domain                       # the domain layer reaches no network, even through helperspure  parse                           # parsing is effect-freeallow Db in db  orders audit_log      # the db layer touches ONLY these tablesallow Net in billing api.stripe.com   # billing talks ONLY to Stripeforbid domain -> infra                # the domain layer must not depend on infra

The report carries the four literal surfaces where a declaration makes them decidable — hosts at Net calls, tables at Db calls (SQL table positions, mirroring the Rust/JVM extractors exactly, plus TypeORM's @Entity("user") declarations read through the receiver's Repository<T> type argument), cmds at Exec, path-shaped paths at Fs — never from a runtime-computed value, propagated transitively, enforced by the allow rules above. On a real Nest app this makes table-level policy live: allow Db in article.service article comments flags the service reaching user and follows.

The classifier is curated (the same under-report-and-say-so posture as the other engines): the Node builtins (fs, net/http/tls, dns, child_process, worker_threads, node:sqlite, node:vm, process.env, the clock), the web network globals (fetch, XMLHttpRequest, navigator.sendBeacon, and WebSocket/EventSource — construction, send and close, charged identically whether they resolve through lib.dom or through @types/node's undici-types re-export), the HTTP/queue/mail tier (axios/got/node-fetch/undici/ws/ socket.io/nodemailer, gaxios + googleapis-common + google-auth-library, stripe, @sentry/*, posthog-node, bull/bullmq), the database drivers (pg/mysql2/mongodb/redis/ioredis/sqlite3/ better-sqlite3/knex) and the ORM tier (TypeORM — with @Entity("…") table extraction — Prisma, Mongoose, Sequelize, drizzle-orm), plus execa/cross-spawn/shelljs/open, fs-extra/ graceful-fs/rimraf/glob/chokidar, dotenv, winston/pino/bunyan. An unlisted npm package contributes nothing — candor never guesses an effect — but the scan names it: the receipt's coverage-ledger line (marker: classifier doesn't cover) lists every package the code demonstrably calls that candor's classifier neither classifies nor has reviewed-pure, and each function carries the invisible list it (transitively) reaches.

⟨0.32⟩ Node core is the one part of the classifier that is a denylist, not a curated list. The builtins are a finite set, so every module's surface is reviewed and a core member that is neither classified nor reviewed effect-free reads Unknown[native:<module>.<member>] — never pure. That is why v8.writeHeapSnapshot() is Fs, inspector.open() is Net, and repl.start(), process.dlopen() and new worker_threads.Worker(file) are visible holes rather than silence.

MCP server — candor as agent ground truth

candor-ts-mcp exposes the read-only queries as an MCP server, so a coding agent can ask "if I change this, what's the runtime blast radius?" or "what reaches the network?" and get deterministic ground truth from a precomputed report — instead of burning tokens tracing the call graph by hand (the measured ~700–2000× token win on blast-radius questions).

jsonc
// in an MCP client config — point it at a report you've already scanned{ "command": "npx", "args": ["-y", "candor-ts-mcp"],  "env": { "CANDOR_REPORT": ".candor/report.myPkg.scan" } }

Tools: candor_impact (backward blast radius), candor_reachable (what runs at runtime), candor_where (effect surface), candor_path (how an effect is reached), candor_callers, candor_show, candor_map, candor_containment, candor_blindspots, candor_whatif (pre-edit gate check — a given-but-unreadable policy is a loud error, never a clean verdict), candor_gate (the checked-in .candor/config policy verdict), candor_accepts (the §6.2 ⟨0.41⟩ proposal that refreshes or adopts accept lines; writes no file, and adopt needs the operator's because), candor_diff/candor_gains (baseline deltas). Each takes an optional report prefix (else $CANDOR_REPORT); --root <dir> locks the server to one workspace. The server is query-only — it never scans (the analyzer self-boundary, spec §7.12: an agent or a hook produces the report; the server reads it, Fs only). The query logic is the shared query-core.mjs, the same answers the CLI gives.

candor-lsp renders the same report where the code is, for any LSP-native editor (helix, neovim; the JetBrains plugin bundles it): a CodeLens per effectful function (⚡ Db, Net · blast radius 12), hover provenance (the hop chain to where an inherited effect is performed), and the repo's policy verdict as diagnostics. Like the MCP server it is a pure report consumer — any engine's report — and never scans. (Both report-computed gates are advisory: the engine's own --gate-json run additionally fails masked/incomplete literal surfaces and is the authoritative CI form.)

It also answers the pre-edit question in place: inside a function, a code action per boundary effect the fn doesn't yet perform — candor: what if handler performed Net? — runs the same whatif as candor-ts-query whatif/candor_whatif (blast radius + the policy rule that WOULD fire) and shows the verdict as a message plus a transient diagnostic at the function (cleared on the file's next open/save; with no policy discovered it says so and reports the radius alone). Plain textDocument/codeAction + workspace/executeCommand (candor.whatif) — it works unmodified in helix, neovim, VS Code, and JetBrains via LSP4IJ.

The live loop — candor-ts-watch keeps the report fresh as the agent edits, so the answers are about the current code, not a stale snapshot:

sh
candor-ts-watch ./src --out .candor/report   # re-scans only when a tracked source actually changes

It tracks the project's sources by content hash and re-scans on a real change (a no-op save or an unrelated write does nothing), writing the same prefix the MCP server reads. So: agent edits → watcher refreshes the report → agent asks candor_impact and gets the post-edit answer. And it reports the edit-delta — not just that the report is fresh but what the edit did to the effect surface (re-scanned (1 changed: app.ts) — Δ f +Net), so the agent learns the consequence of its own change. v1 runs a full (sound) scan per change; the deeper perf optimisation — re-analysing only the changed file's subgraph instead of the whole project — is the staged next step (the content-hash gate is its first increment).

Trust contract (spec §4)

Anything candor-ts can't resolve is designed to read Unknown, never silently pure — known open gaps are listed in candor-spec's SOUNDNESS.md (e.g. R780, R803, R804): a function-valued parameter or field being called, an any-typed callee, resolution landing on a type rather than a body.

An uncurated dependency can opt out of Unknown/silent-pure by declaring its effects in its package.json — "candorEffects": ["Net"] (spec §5.1, the effect manifest). candor-ts reads it as the declared-not-verified tier: the package's calls classify to the declared set, and it stops being a coverage-ledger blind spot. A name outside the §1 vocabulary voids the declaration loudly (a typo must not silently narrow a surface). And candor-ts-query gains <cur> <base> flags the supply-chain delta — the effects a surface gained between two reports. Real-world consequence, measured on rimraf (50 files, 55 functions analyzed): its DI-style fs injection means many functions read Unknown, disclosed — that's the contract working, not noise. The report says "can reach", never "does"; an absent literal is never a claim of absence.

Framework dependency injection (spec §2's bounded-CHA clause). rimraf's injection is a function-valued parameter, which reads Unknown. A DI container is measured separately, on NestJS 10 with an executed fixture:

  • a provider entry { provide: Store, useClass | useValue | useFactory | useExisting: … } whose token is a project CLASS is read as a conversion: the substitute joins Store's candidates, so this.store.save() is charged the union of Store.save and the substitute's save (SOUNDNESS R1061 — silent before, all three forms executed);

  • a parameter typed by an INTERFACE (@Inject("SINK") sink: Sink) dispatches over the project's visible implementors of Sink, so a useClass that implements Sink is charged; a useValue object literal that implements nothing reads Unknown (dispatch:).

  • the TOKEN is read through the checker's type, so const TOK = Store, an imported token, TOKENS.store and a .map over [Store] name Store; a helper's token/impl parameter is read through its visible call sites; a token typed Function/Type<any> joins its substitute to every project class it is assignable to (R1061);

  • a substitute the scan cannot name (useClass: impls[i] typed Type<Store>, a useValue typed any) makes a dispatch on the token class read Unknown (dispatch:).

Named miss: a provider list the scan cannot see at all (one imported from an unscanned package) and a substitute supplied by a dependency for a token the dependency owns. Gate a DI-heavy service with deny <E> Unknown as well as deny <E>.

Cross-engine consistency — machine-checked

candor-ts is one of the four code engines (with the reference engine candor-java, the Rust engines, and candor-swift) held together by the spec's cross-engine conformance suite: the shared effect-set oracle, the §6.2 policy-grammar battery (including allow Db), the §3.1 query-shape and match-ladder checks, the gate exit-code contracts, and the newer parts up through the pure-vs-Unknown ruling (PART 16) — the engines must answer identically, on every push to the spec.

What the analysis core implements (and where the spec told it how)

PieceSpec source
Resolve every call via the compiler API (getResolvedSignature), never syntaxCLASSIFIER §1
The classifier maps the resolved target's module (node:fs→Fs, node:net→Net, …)CLASSIFIER §2, TS notes
process.env property read → Env; Date.now → ClockSPEC §1
Local edges (cross-file) + least-fixpoint propagationSEMANTICS §5a
Closure bodies attribute to the nearest enclosing functionSEMANTICS §2
A call resolving to a type (function-typed field/param) → Unknown, never silent-pureSPEC §4
Unmatched external calls contribute nothing (curated-classifier caveat)SEMANTICS §8 C1
The literal surfaces hosts/cmds/paths/tables, literal-read onlySPEC §2
{ candor: { version, toolchain, spec: "0.41" }, functions } envelope; pure fns omittedSPEC §2/§2.1
Call-graph sidecar with every analyzed function a keySPEC §2.2
The gate: AS-EFF-006 / 008 / 009, loud on an unreadable policySPEC §6.2

Origin: the derivability proof

This engine began as a deliberately minimal single-file slice written from the spec documents alone (SPEC.md, SEMANTICS.md, CLASSIFIER.md) — without consulting the Rust or JVM sources — to answer executably: is the spec enough to derive a new-language implementation? Yes — 20/20 on the shared oracle. That clean-room claim is frozen at commit a29b152; everything since (multi-file projects, the query surface, the gate, the literal surfaces) is spec-implemented but post-hoc, and its guarantee is the conformance differential above, not clean-room provenance. The one engine-fix the original derivation needed (a call landing on a function-type declaration read as pure until §4 was applied to it) remains the proof point: the fix was "do what §4 says", not "go read the Rust source".

Status

Speaking candor-spec 0.41 (the package version is in package.json): the analysis core, the gate (--policy / --gate-json / .candor/config), the full §3.1 query surface (including containment, blindspots, the --include-unknown dispatch frontier, and ⟨0.24⟩ gate --report — the gate applied to an EXISTING report, byte-equivalent to scan --policy's verdict), the MCP server, the LSP server, and the watch loop are real, behaviorally tested (npm test — the behavioral suite across six harnesses), soundness-fuzzed with verified teeth (node fuzz.mjs — spec §7.13: generated effect chains through every encoded call form, any silent-pure = red), and conformance-held against the Rust/JVM/Swift engines. The npm classifier tier is deliberately curated and keeps growing case-by-case. Entry points (Nest/Next populations), unknownWhy origins, reachable, cross-package inheritance (CANDOR_DEPS + the spec §2 hash, version-trusted per §2.1), and --allow-js are all in. On npm: npx -y candor-ts <dir>. Per-release detail (⚠ marks report/verdict-affecting changes): CHANGELOG.md.

Development

No build step — the engine runs on Node directly.

sh
npm installnpm test            # the full CI gate: lint + unit (node:test) + behavioural + MCP + watch + the                    # fabrication probe + the §7.13 soundness fuzzernpm run test:unit   # just the native unit tests — the query algebra + policy DSL + the scan-core                    # classifier/literal leaves (query-core / policy / scan-core)npm run lint        # eslint (the recommended ruleset; the CI lint gate)node scan.mjs <dir | file.ts | tsconfig.json> --out .candor/report   # scan a project

The pure cores are factored into importable modules — query-core.mjs (the §3.1 queries), policy.mjs (the §6.2 DSL + literal matchers), and scan-core.mjs (the classifier + the SQL/ command/host extractors) — so they're unit-tested directly; the TS-compiler-driven walk stays in scan.mjs.

Agents: install candor as an MCP server

candor-ts ships candor's read-only query surface as an MCP server, so an agent asks "what is the blast radius of changing this?" or "what reaches the network?" and gets a deterministic answer from a precomputed report instead of grepping for it.

bash
npx -y candor-ts --mcp        # the server, over stdiocandor mcp install            # or let the umbrella write/merge .mcp.json for you

Registration instructions come from the package you already installed — candor mcp --help prints the .mcp.json snippet and the claude mcp add line, and candor mcp install writes them. There is no remote file to fetch, tamper with, or auto-execute, and nothing here tells an agent to run anything it did not already choose to install.

Discovery is passive: the manifest is server.json, published to the official MCP Registry so clients and directories can find candor without being handed a script.

The registry verifies namespace ownership from the mcpName field in package.json — that is the npm mechanism. (A mcp-name: README marker is the crates.io convention and does nothing here; the first cut of this used it, and the registry refused the publish with missing required 'mcpName' field. The line below is kept only because it is how a human greps for the namespace.)

mcp-name: io.github.tombaldwin/candor

來源:README.md,提交 ca86f53

工具

17

candor_impact

Backward blast radius: every effectful function that transitively calls `fn`, and which runtime entry points are downstream. Answers 'if I change this, what surfaces at runtime?' — the cheapest possible alternative to tracing callers by hand.

輸入參數fn必填report

candor_where

Which functions perform a given effect (e.g. Net, Db, Exec, Fs) — `directly` vs `inherited` via a callee. The effect-surface map.

輸入參數effect必填report

candor_reachable

What the program/fleet actually DOES at runtime: effects unioned over the entry points, with how many roots reach each and via which.

輸入參數report

candor_path

Forward provenance: the shortest call chain from `fn` to the nearest function that performs `effect` DIRECTLY — 'this reaches Net through WHAT?'.

輸入參數fn必填effect必填report

candor_callers

Who calls `fn` — direct (one hop) and transitive callers over the effect-relevant call graph.

輸入參數fn必填report

candor_show

A function's effects (inferred = transitive, direct = own body) plus its literal surfaces (hosts/cmds/paths/tables) when present.

輸入參數fn必填report

candor_map

Per-module effect overview: each module's union of effects and function count. The architecture-at-a-glance.

輸入參數report

candor_whatif

Hypothetically add `effect` to `fn` and report the blast radius; with `policy`, also the deny-rule violations it would cause. Pre-edit gate check. ALWAYS CHECK for the presence of `ok`, never just its value: over a report this route cannot fully evaluate, `ok` is ABSENT and `{incomplete:true, ...}` takes its place — `affected`/`violations` still ship (a partial answer beats a refusal; this tool is consulted BEFORE an edit), but neither `true` nor `false` is a claim the input licenses. The causes are the same ones `candor_gate`/`candor_unverified` disclose: `unanalyzed` (candor could not read a file of the target's own code), `outOfScope` (the peek found a denied effect outside the scan's reach), `unread` (a class the scan never opened — gated on this call's OWN `deny`/`pure` rules, since only those depend on code outside the scan's scope), and `unaskedRules` (a class something DID open, but under a narrower deny set than this policy's own).

輸入參數fn必填effect必填policyreport

candor_fix

THE BOUNDARY FIX: when `fn` performs `effect` in a layer the policy forbids (a violation candor_whatif/candor_gate reports), compute the architectural REMEDY — not just 'the domain can't do Net', but WHERE the effect belongs and the refactor to put it there: the direct call site to hoist, the forbidden-layer functions that become pure and thread the value as a parameter, and the nearest allowed-layer caller to perform the effect ({ crossing, site, deniedSpan, hoistTo, policyAlternative }). The remedial inverse of candor_whatif. Call this INSTEAD OF guessing a fix (adding `allow` to the domain, moving the I/O one call up, threading a handle the wrong way). Advisory: it names the structure, you write the code; the gate re-scan verifies. Uses `policy` if given, else the repo's checked-in .candor/config policy (spec §3.4). ALWAYS CHECK `refused` BEFORE `crossing`: where the policy narrows on evidence this report does not carry, candor_gate REFUSES and no remedy is computed — the result is `{ fn, effect, refused:true, unevaluated:[{rule, why}] }` WITH NO `crossing` KEY, an absent key rather than `crossing:false`, because 'no boundary fix needed' is a claim and that is the one thing the tool cannot claim here (spec §3.2: an advisory verb may be LESS certain than the gate, never MORE). Re-scan so the report carries the narrowing evidence, or widen the rule; do not read the missing plan as an all-clear.

輸入參數fn必填effect必填policyreport

candor_gate

The policy verdict over this report: { ok, violations:[{rule, fn, effects, detail}] } — 'would this repo pass its architecture gate?'. Uses `policy` if given, else the repo's checked-in .candor/config policy (spec §3.4). ALWAYS CHECK `ok`, never the length of `violations`: a rule whose narrowing evidence the report does not carry is NOT EVALUATED, and then the result is `{ ok:false, refused:true, reason, unevaluated:[{rule, why}] }` WITH NO `violations` KEY — an absent key, not an empty list, because the gate is making no claim there. `unevaluated` also rides a firing verdict (a certain violation dominates a refusal). `incomplete:true` means the gate CANNOT be green, and the key beside it says which of the four causes fired: `unanalyzed` (the report declares code candor could not analyze), `outOfScope` (the producer's peek NAMED a function outside the scan's scope performing an effect this policy denies), `unread` (a class the producing scan never OPENED — its effects are absent because nothing looked, not because there are none; re-scan those sources WITH this policy), or `unaskedRules` (a class the producing scan's peek DID read, but under a deny set that does not cover this one — re-scan under THE SAME policy this tool is applying, not merely under a policy). Computed from the report — the engine's own --gate-json run is the authoritative CI form: it additionally fails an allow rule whose literal surface is INCOMPLETE (a masked/invisible endpoint), which is not a report field, so a green here can still be red in CI.

輸入參數policyreport

candor_accepts

SPEC §6.2 ⟨0.41⟩ `accepts`: PROPOSE a refreshed policy — stale `accept` lines deleted, over-wide ones narrowed, exceeded ones proposed in a comment — as `{ mode, text, removed, narrowed, proposals, unnamed, unjudged, ignored, after, written:false, notes }`. It is the engine's own `accepts` verb (run in-process through the same code as `candor-ts-query accepts --json`, so the proposal is the CLI's, not a second implementation) and it WRITES NO FILE: `text` is the proposed policy, for a human to diff and commit. With `adopt:true` it also proposes a new `accept` line for each violation no entry names, and then `because` is REQUIRED — the operator's reason, written on every line it creates. NEVER INVENT A REASON: the engine does not compose one and neither may you; if the operator has not given you a reason, ask them. The reason you pass is echoed back as `adoptedBecause` so the operator can see exactly what was written in their name. Uses `policy` if given, else the repo's checked-in .candor/config policy. A stale report yields the STALE header like every tool here (re-scan first: a proposal over old code would accept the wrong rows). An incomplete or refused gate yields a tool error and no proposal.

輸入參數adoptpolicyreportbecause

candor_unverified

PROVABLE-PURITY check (INSTANT): a `pure`/`deny <E>` policy layer PASSES a function that has no such effect — but if that function is Unknown (candor couldn't resolve one of its calls), the pass is UNVERIFIED: the Unknown could hide the very effect the rule forbids. The classic case is a fn/closure-injected 'port' — the domain reads as Unknown, so `deny Net domain`/`pure domain` clear it though it may reach Net at runtime. Returns each such function + the `deny <E> Unknown <scope>` upgrade that makes the layer PROVABLY clean. Uses `policy` if given, else the repo's checked-in .candor/config policy. ALWAYS CHECK `ok`, never the length of `unverified`: over a report declaring code candor could NOT analyze, `ok` IS ABSENT and `{incomplete:true, unanalyzed}` takes its place — a function in an unanalyzed file is missing from the report entirely, so it cannot be enumerated as an unverified pass, and an empty array there is not an all-clear (spec §3.2). `incomplete:true` also rides the three SCOPE causes, on the same terms as candor_gate: `outOfScope` (the producer's peek named a function outside the scan's scope performing a denied effect), `unread` (a class the producing scan never OPENED — re-scan those sources WITH this policy), and `unaskedRules` (a class the producing scan's peek DID read, but under a deny set that does not cover this one — re-scan under THE SAME policy this tool is applying, not merely under a policy). `ok` is ABSENT for a further reason too, and the entries that come with it are the sharpest ones: where the policy narrows on evidence this report does not carry, candor_gate REFUSES — and this verb then NAMES each function the gate could not judge, as `{fn, rule, why}` where `why` is THE MISSING EVIDENCE and never a derived class, plus the gate's own `unevaluated:[{rule, why}]`. Those entries carry no `upgrade`: whether they pass at all is the open question, so there is nothing to upgrade yet — re-scan so the report carries the evidence, or widen the

輸入參數policyreport

candor_containment

Per boundary effect (Db/Net/Exec/Fs/Ipc/Clipboard): how contained it is in one architectural layer — the dispersion diagnostic (spec §6.1). Not a score; per-effect facts.

輸入參數report

candor_blindspots

The Unknown SOURCES — calls the engine genuinely could not resolve (reflection, wide dispatch, fn-pointers) — ranked by how many functions inherit Unknown through each. Turns a high-Unknown report into a short worklist.

輸入參數report

candor_diff

The per-function effect delta versus a baseline report: gained (introduced vs inherited) and lost effects. 'What did this change do to the effect surface?'.

輸入參數reportbaseline必填

candor_gains

The supply-chain alarm: effects the surface GAINED versus a baseline (package-level + per-function) — 'did this dependency bump add Net/Exec somewhere?'.

輸入參數reportbaseline必填

candor_activity

What the edit-time gate caught: MEASURED activity from .candor/activity.jsonl (the Stop-hook / standalone review log) — edits checked, verdicts, violations by AS-EFF code, effects introduced, largest blast radius, deepest propagation (hops), plus the most recent records. Counted from the log, no model. A missing log is an empty result (the loop isn't wired here — not an error); corrupt lines are skipped.

輸入參數loglimitsincesession

版本歷史

21
  1. v0.41.3最新Nov 7, 2026
  2. v0.41.0Nov 4, 2026
  3. v0.40.18Oct 31, 2026
  4. v0.40.17Oct 26, 2026
  5. v0.40.16Oct 25, 2026
  6. v0.40.15Oct 22, 2026
  7. v0.40.12Oct 16, 2026
  8. v0.40.10Oct 14, 2026
  9. v0.40.9Oct 13, 2026
  10. v0.40.8Oct 13, 2026
  11. v0.40.7Oct 12, 2026
  12. v0.40.6Oct 11, 2026
  13. v0.40.5Oct 11, 2026
  14. v0.40.4Oct 10, 2026
  15. v0.40.2Oct 9, 2026
  16. v0.40.1Oct 9, 2026
  17. v0.40.0Oct 8, 2026
  18. v0.39.1Sep 21, 2026
  19. v0.39.0Sep 20, 2026
  20. v0.38.3Sep 16, 2026
  21. v0.38.0Sep 16, 2026

評分

已滿足適用檢查項的 90%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分
  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分

其他 Candor 整合