alphacouncil-agent 1.0.13 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,14 +6,14 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "AlphaCouncil plugins for public-equity research.",
9
- "version": "1.0.13"
9
+ "version": "1.0.15"
10
10
  },
11
11
  "plugins": [
12
12
  {
13
13
  "name": "alphacouncil-agent",
14
14
  "source": "./",
15
15
  "description": "Multi-agent company, ETF and index research: evidence packets, method seats, bull/bear debate and portfolio-manager synthesis.",
16
- "version": "1.0.13",
16
+ "version": "1.0.15",
17
17
  "author": {
18
18
  "name": "Zhao73"
19
19
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alphacouncil-agent",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "Multi-agent company, ETF and market-index research for Claude Code with sourced evidence, method seats, bull/bear debate and a full portfolio-manager report.",
5
5
  "author": {
6
6
  "name": "Zhao73"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alphacouncil-agent",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "Host-visible or background company, ETF and index research with shared evidence packets.",
5
5
  "author": {
6
6
  "name": "Zhao73"
package/CHANGELOG.md CHANGED
@@ -2,6 +2,38 @@
2
2
 
3
3
  Notable changes per release. Dates are UTC.
4
4
 
5
+ ## [1.0.15] — 2026-07-30
6
+
7
+ ### Changed
8
+
9
+ - **Listed in the official MCP Registry** as `io.github.Zhao73/alphacouncil-agent`:
10
+ `server.json` added, and package.json carries the `mcpName` field the registry uses to
11
+ verify npm ownership. No runtime change.
12
+
13
+ ## [1.0.14] — 2026-07-30
14
+
15
+ ### Changed
16
+
17
+ - **Method seats speak like a person with a view, not a form being filled.** The voice
18
+ worker is now instructed to write each of the five first-person fields as two to four
19
+ complete sentences in the method's own characteristic register — what it reaches for
20
+ first, the standard it holds the number to, and why this number settles it — and those
21
+ five fields are exempt from fast-tier prose compression, because they are the worker's
22
+ deliverable, not restatement.
23
+ - **An abstaining seat now explains itself in first person instead of reciting a gate
24
+ code.** Both deterministic abstention templates (gate-closed and record-missing) grew
25
+ from one formula sentence into a short statement of the method's own discipline: what it
26
+ checks first, what was absent this round, why guessing without it would stop being a
27
+ method, and that the seat returns the moment the inputs arrive. The load-bearing
28
+ sentence — an abstention is neither bearish nor a vote against the asset — is unchanged
29
+ in every language.
30
+ - **The bench no longer glues twenty-five abstaining seats into one run-on paragraph.**
31
+ Each abstained or declined seat renders as its own quoted block under its own name, and
32
+ a per-seat statement composed from the five voice fields renders as labelled lines
33
+ rather than one joined sentence.
34
+ - The READMEs document `ALPHACOUNCIL_VOICE_ABSTAINING_SEATS=1` for operators who want
35
+ abstaining seats voiced by a full worker as well.
36
+
5
37
  ## [1.0.13] — 2026-07-30
6
38
 
7
39
  ### Fixed
package/README.md CHANGED
@@ -354,6 +354,12 @@ macro — and receive the analyst packets separately, labelled as other seats' r
354
354
  than as fact. That separation is the point: the bench is worth having only because Munger
355
355
  looks at incentives where an analyst looked at margins. See [docs/attribution.md](docs/attribution.md).
356
356
 
357
+ A seat that reached a stance gets its own isolated voice worker and speaks in first person —
358
+ what it sees, how its standard reads the number, whether it would act, and what would change
359
+ its mind. A seat that abstained publishes a deterministic first-person statement at zero
360
+ model cost; set `ALPHACOUNCIL_VOICE_ABSTAINING_SEATS=1` to give abstaining seats a full
361
+ voice worker too, at the cost of one worker per abstained seat.
362
+
357
363
  ## 🧩 Architecture
358
364
 
359
365
  The diagram below is the full/deep path. Quick retains the Master Bench but uses its fixed
package/README.zh-CN.md CHANGED
@@ -293,6 +293,8 @@ Claude Code、OpenCode、Grok Build 装完即可用。Codex 的 prompts 是用
293
293
 
294
294
  大师读到的是**和分析师同一份已确立事实**(申报、行情、财务、宏观),分析师的证据包单独给出并标注为「其他席位的解读」而非事实。这个分离是关键:芒格看激励结构的地方分析师看的是毛利率,只有让他们各自取舍,这个议席才有存在意义。详见 [docs/attribution.md](docs/attribution.md)。
295
295
 
296
+ 形成立场的席位各自有一个隔离的发声 worker,用第一人称把话说完整——我看到什么、用我的标准怎么读这个数、我会不会动手、什么会让我改主意。弃权席位则以零模型成本发布一段确定性的第一人称陈述;想让弃权席也由 worker 完整开口,设 `ALPHACOUNCIL_VOICE_ABSTAINING_SEATS=1`(代价是每个弃权席多花一个 worker)。
297
+
296
298
  ## 🧩 架构
297
299
 
298
300
  下图是完整/deep 路径。Quick 仍包含 Master Bench,但改用固定四证据席、一轮并行
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schema_version": 1,
3
3
  "channel": "solo_test",
4
- "package_version": "1.0.13",
4
+ "package_version": "1.0.15",
5
5
  "persona_pack_version": "0.9.4",
6
6
  "pack_root": "knowledge/solo-test/masters",
7
7
  "assurance_class": "provisional_derived_proxy",
@@ -9,7 +9,7 @@ import { compiledPersonaPacks } from "./personas-v3/registry.mjs";
9
9
  import { bullets, clip, clipAtBoundary, fence } from "./text.mjs";
10
10
  import { completenessStatus, validateFinalReport, verificationStatus, withCompletenessBanner, withDisclaimer, withVerificationBanner } from "./gates.mjs";
11
11
  import { isFundOrIndex } from "./instruments.mjs";
12
- import { intentLabel, VOICE_FIELDS, voiceDisclaimer, voiceFieldLabel } from "./voice.mjs";
12
+ import { composeVoiceStatement, intentLabel, VOICE_FIELDS, voiceDisclaimer, voiceFieldLabel } from "./voice.mjs";
13
13
  import { agentState, appendEvent, artifactPaths, runPath, taskState } from "./run-store.mjs";
14
14
  import { personaTitle, registry } from "./personas/registry.mjs";
15
15
 
@@ -100,7 +100,18 @@ export function renderMasterMarkdown(opinion, lang) {
100
100
  opinion.thread_id ? `- Visible thread ID: ${opinion.thread_id}` : "",
101
101
  "",
102
102
  `### ${labels.statement}`,
103
- opinion.voice_statement || opinion.summary || "",
103
+ // When the statement was composed from the five voice fields, render those fields as
104
+ // labelled lines -- a person reasoning, not one glued sentence. A statement from any
105
+ // other origin (a flat worker statement, a deterministic template) is the authored
106
+ // record and renders verbatim; the fields beside it may be a deterministic fallback
107
+ // that would silently replace what the worker actually said.
108
+ ...(opinion.voice && typeof opinion.voice === "object"
109
+ && composeVoiceStatement(opinion.voice, lang) === opinion.voice_statement
110
+ ? VOICE_FIELDS
111
+ .map((field) => [field, String(opinion.voice[field] ?? "").trim()])
112
+ .filter(([, text]) => text)
113
+ .map(([field, text]) => `**${voiceFieldLabel(field, lang)}**: ${text}`)
114
+ : [opinion.voice_statement || opinion.summary || ""]),
104
115
  "",
105
116
  `### ${labels.summary}`,
106
117
  opinion.deterministic_summary || opinion.summary || "",
@@ -207,11 +218,13 @@ function renderMasterStatements(run) {
207
218
  // input" tells a reader the system broke when the method spoke. A seat whose required
208
219
  // fact never arrived genuinely is a gap. Rendering them together made every run read as
209
220
  // the second kind, which is the complaint this split exists to answer.
210
- // One paragraph each, not one row per seat: the stable IDs stay visible so the gate and
211
- // the reader can both account for every selected seat.
221
+ // One block per seat, not twenty-five names glued into a run-on paragraph: each seat
222
+ // speaks its own statement, because a reader asked for the bench precisely to hear each
223
+ // method say in its own words why this is or is not its call. The stable IDs stay
224
+ // visible so the gate and the reader can both account for every selected seat.
212
225
  const merged = (group) => group
213
- .map((opinion) => `${masterTitle(opinion.master, run.language)} (\`${opinion.master}\`) \u2014 ${opinion.voice_statement}`)
214
- .join(" ");
226
+ .map((opinion) => `**${masterTitle(opinion.master, run.language)}** (\`${opinion.master}\`)\n\n> ${opinion.voice_statement}`)
227
+ .join("\n\n");
215
228
  const declined = abstained.filter((opinion) => methodDeclined(opinion));
216
229
  const ungrounded = abstained.filter((opinion) => !methodDeclined(opinion));
217
230
  if (declined.length) {
@@ -249,10 +249,10 @@ export function completedMasterOpinion(run, item) {
249
249
  const label = displayMasterLabel(item.pack.admitted_label?.[locale]
250
250
  || item.pack.admitted_label?.en || item.id);
251
251
  const copy = localized(run.language, {
252
- en: { abstain: (reasons) => `Using the ${label} method, I do not issue a directional view on ${run.symbol} in this run: the method gate did not open (${reasons}). This is neither bearish nor a vote against the asset; the seat reassesses only once that gate can be satisfied.`, withheld: (pct) => `${pct}% coverage; score withheld`, unscored: "not scored", verdict: (stance, reason) => `${label} frozen decision: ${stance} (${reason})`, summary: (score) => `Using the ${label} method on ${run.symbol}, the PersonaPack v3 deterministic policy executed with score ${score}. Typed facts, hard vetoes, and score bands produced this stance; no language model selected it.`, hit: (id) => `score hit: ${id}`, miss: (id) => `score miss: ${id}`, eligibility: (id) => `eligibility condition ${id} becomes satisfied`, veto: (id) => `hard veto ${id} no longer triggers`, score: (id) => `score condition ${id} becomes satisfied` },
253
- zh: { abstain: (reasons) => `按${label}方法审视 ${run.symbol},本轮不作方向判断:方法闸门未打开(${reasons})。这不是看空,也不是一张反对票;只有该闸门可被满足后,该席位才会重新评估。`, withheld: (pct) => `覆盖率 ${pct}%,分数被保留不发布`, unscored: "未评分", verdict: (stance, reason) => `${label}的冻结结论:${stance}(${reason})`, summary: (score) => `按${label}方法审视 ${run.symbol}:PersonaPack v3 确定性政策已执行,得分 ${score}。该立场由结构化事实、硬否决和评分带产生,没有让语言模型选择立场。`, hit: (id) => `评分命中:${id}`, miss: (id) => `评分未命中:${id}`, eligibility: (id) => `资格条件 ${id} 变为满足`, veto: (id) => `硬否决 ${id} 不再触发`, score: (id) => `评分条件 ${id} 变为满足` },
254
- ja: { abstain: (reasons) => `${label}の方法では、メソッドのゲートが開かなかったため(${reasons})、今回は ${run.symbol} の方向判断を出しません。弱気判断や反対票ではなく、そのゲートが満たせるようになった時点で再評価します。`, withheld: (pct) => `カバレッジ ${pct}% のためスコアは非公開`, unscored: "未採点", verdict: (stance, reason) => `${label}の凍結済み判断:${stance}(${reason})`, summary: (score) => `${label}の方法で ${run.symbol} を評価し、PersonaPack v3 の決定論的ポリシーを実行した結果、スコアは ${score}。構造化事実、ハード拒否条件、スコア帯がこの立場を生成しており、言語モデルは立場を選択していない。`, hit: (id) => `採点条件を満たす:${id}`, miss: (id) => `採点条件を満たさない:${id}`, eligibility: (id) => `適格条件 ${id} が満たされる`, veto: (id) => `ハード拒否条件 ${id} が解除される`, score: (id) => `採点条件 ${id} が満たされる` },
255
- ko: { abstain: (reasons) => `${label} 방법으로는 방법론 게이트가 열리지 않아(${reasons}) 이번 실행에서 ${run.symbol}의 방향 판단을 내리지 않습니다. 이는 약세 판단이나 반대표가 아니며, 해당 게이트가 충족될 있을 때에만 재평가합니다.`, withheld: (pct) => `커버리지 ${pct}%로 점수를 공개하지 않음`, unscored: "미채점", verdict: (stance, reason) => `${label}의 동결된 판단: ${stance}(${reason})`, summary: (score) => `${label} 방법으로 ${run.symbol}을 검토하여 PersonaPack v3 결정론적 정책을 실행했으며 점수는 ${score}입니다. 구조화된 사실, 하드 거부 조건, 점수 구간이 이 입장을 만들었고 언어 모델은 입장을 선택하지 않았습니다.`, hit: (id) => `점수 조건 충족: ${id}`, miss: (id) => `점수 조건 미충족: ${id}`, eligibility: (id) => `적격 조건 ${id} 충족`, veto: (id) => `하드 거부 조건 ${id} 해제`, score: (id) => `점수 조건 ${id} 충족` },
252
+ en: { abstain: (reasons) => `Speaking through the ${label} method: the first thing my discipline checks is whether the inputs it runs on are actually on the table, and this round they were not -- the method gate did not open (${reasons}). So I issue no directional view on ${run.symbol} in this run. Read that precisely: it is neither bearish nor a vote against the asset -- a method that guesses without its inputs stops being a method. Put those inputs in front of me and this seat returns to the table at once.`, withheld: (pct) => `${pct}% coverage; score withheld`, unscored: "not scored", verdict: (stance, reason) => `${label} frozen decision: ${stance} (${reason})`, summary: (score) => `Using the ${label} method on ${run.symbol}, the PersonaPack v3 deterministic policy executed with score ${score}. Typed facts, hard vetoes, and score bands produced this stance; no language model selected it.`, hit: (id) => `score hit: ${id}`, miss: (id) => `score miss: ${id}`, eligibility: (id) => `eligibility condition ${id} becomes satisfied`, veto: (id) => `hard veto ${id} no longer triggers`, score: (id) => `score condition ${id} becomes satisfied` },
253
+ zh: { abstain: (reasons) => `按${label}方法发言:我的纪律第一步是确认方法赖以运转的输入是否都在桌上,这一轮它们没有到齐——方法闸门未打开(${reasons})。所以我对 ${run.symbol} 本轮不给方向判断。请准确理解:这不是看空,也不是一张反对票——缺着输入硬猜,方法就不再是方法。把这些输入摆到我面前,这个席位立刻回到桌上重新评估。`, withheld: (pct) => `覆盖率 ${pct}%,分数被保留不发布`, unscored: "未评分", verdict: (stance, reason) => `${label}的冻结结论:${stance}(${reason})`, summary: (score) => `按${label}方法审视 ${run.symbol}:PersonaPack v3 确定性政策已执行,得分 ${score}。该立场由结构化事实、硬否决和评分带产生,没有让语言模型选择立场。`, hit: (id) => `评分命中:${id}`, miss: (id) => `评分未命中:${id}`, eligibility: (id) => `资格条件 ${id} 变为满足`, veto: (id) => `硬否决 ${id} 不再触发`, score: (id) => `评分条件 ${id} 变为满足` },
254
+ ja: { abstain: (reasons) => `${label}の方法として発言します。私の規律がまず確認するのは、方法が拠って立つ入力が実際に揃っているかどうかであり、今回はそれが揃いませんでした——メソッドのゲートが開いていません(${reasons})。したがって今回は ${run.symbol} の方向判断を出しません。正確に読んでください。これは弱気判断でも反対票でもありません——入力なしに推測すれば、それはもはや方法ではないからです。この入力が揃い次第、この席は直ちに再評価に戻ります。`, withheld: (pct) => `カバレッジ ${pct}% のためスコアは非公開`, unscored: "未採点", verdict: (stance, reason) => `${label}の凍結済み判断:${stance}(${reason})`, summary: (score) => `${label}の方法で ${run.symbol} を評価し、PersonaPack v3 の決定論的ポリシーを実行した結果、スコアは ${score}。構造化事実、ハード拒否条件、スコア帯がこの立場を生成しており、言語モデルは立場を選択していない。`, hit: (id) => `採点条件を満たす:${id}`, miss: (id) => `採点条件を満たさない:${id}`, eligibility: (id) => `適格条件 ${id} が満たされる`, veto: (id) => `ハード拒否条件 ${id} が解除される`, score: (id) => `採点条件 ${id} が満たされる` },
255
+ ko: { abstain: (reasons) => `${label} 방법으로 말합니다. 제 원칙이 가장 먼저 확인하는 것은 방법이 딛고 서는 입력이 실제로 갖춰졌는가이며, 이번에는 갖춰지지 않았습니다 — 방법 게이트가 열리지 않았습니다(${reasons}). 따라서 이번 실행에서 ${run.symbol}의 방향 판단을 내리지 않습니다. 정확히 읽어 주십시오. 이는 약세 판단도 반대표도 아닙니다 입력 없이 추측하면 그것은 이상 방법이 아니기 때문입니다. 이 입력이 갖춰지는 즉시 이 좌석은 곧바로 재평가로 돌아옵니다.`, withheld: (pct) => `커버리지 ${pct}%로 점수를 공개하지 않음`, unscored: "미채점", verdict: (stance, reason) => `${label}의 동결된 판단: ${stance}(${reason})`, summary: (score) => `${label} 방법으로 ${run.symbol}을 검토하여 PersonaPack v3 결정론적 정책을 실행했으며 점수는 ${score}입니다. 구조화된 사실, 하드 거부 조건, 점수 구간이 이 입장을 만들었고 언어 모델은 입장을 선택하지 않았습니다.`, hit: (id) => `점수 조건 충족: ${id}`, miss: (id) => `점수 조건 미충족: ${id}`, eligibility: (id) => `적격 조건 ${id} 충족`, veto: (id) => `하드 거부 조건 ${id} 해제`, score: (id) => `점수 조건 ${id} 충족` },
256
256
  });
257
257
  // Every condition id in a frozen decision was hashed before the policy ran so the decision
258
258
  // layer could not recognise the seat. Past this point the seat is named in the report and in
@@ -364,10 +364,10 @@ export function declinedMasterOpinion(run, item) {
364
364
  const fundOrIndex = instrument?.fund_like === true || instrument?.index_like === true
365
365
  || ["etf", "mutual_fund", "index"].includes(instrument?.asset_type);
366
366
  const copy = localized(run.language, {
367
- en: { none: "none", verdict: `${label} cannot evaluate ${run.symbol}: ${eligibility.reason}`, summary: (missing) => `The v3 typed-fact gate returned ${eligibility.status}; missing: ${missing}. No legacy prompt or narrative decision layer was called.`, fundContext: fundOrIndex ? `${run.symbol} is classified as ${instrument.asset_type}; this method must use dated holdings or aggregate index evidence rather than treating the instrument as an operating company. ` : "", statement: (missing, context) => `${context}Using the ${label} method, I do not issue a directional view on ${run.symbol} in this run because the point-in-time record lacks ${missing}. This is neither bearish nor a vote against the asset. I would reassess only after those method-critical facts are available.`, available: (id) => `${id} becomes available from a point-in-time source` },
368
- zh: { none: "无", verdict: `${label}无法评估 ${run.symbol}:${eligibility.reason}`, summary: (missing) => `v3 typed-fact 闸门返回 ${eligibility.status};缺失:${missing}。系统未调用旧提示词或叙述决策层。`, fundContext: fundOrIndex ? `${run.symbol} 已识别为 ${instrument.asset_type};该方法必须通过带时点的持仓穿透或指数聚合证据使用,不能把它当成经营公司。` : "", statement: (missing, context) => `${context}按${label}方法审视 ${run.symbol},本轮不作方向判断,因为时点一致的资料缺少:${missing}。这不是看空,也不是一张反对票;只有取得这些方法关键事实后,该席位才会重新评估。`, available: (id) => `${id} 可从时点一致的来源取得` },
369
- ja: { none: "なし", verdict: `${label}は ${run.symbol} を評価できません:${eligibility.reason}`, summary: (missing) => `v3 typed-fact ゲートは ${eligibility.status} を返しました。欠落:${missing}。旧プロンプトや叙述型の判断層は呼び出していません。`, fundContext: fundOrIndex ? `${run.symbol} は ${instrument.asset_type} に分類されており、事業会社として扱わず、基準日付き保有銘柄のルックスルーまたは指数集計証拠を用いる必要があります。` : "", statement: (missing, context) => `${context}${label}の方法では、時点整合した資料に ${missing} が欠けているため、今回は ${run.symbol} の方向判断を出しません。弱気判断や反対票ではなく、これらの方法上重要な事実が揃った時点で再評価します。`, available: (id) => `${id} が時点整合した出典から利用可能になる` },
370
- ko: { none: "없음", verdict: `${label}은 ${run.symbol}을 평가할 수 없습니다: ${eligibility.reason}`, summary: (missing) => `v3 typed-fact 게이트가 ${eligibility.status}을 반환했습니다. 누락: ${missing}. 기존 프롬프트나 서술형 판단 계층은 호출하지 않았습니다.`, fundContext: fundOrIndex ? `${run.symbol}은 ${instrument.asset_type}로 분류되므로 영업회사처럼 취급하지 않고 기준일이 있는 보유 종목 룩스루 또는 지수 집계 증거를 사용해야 합니다. ` : "", statement: (missing, context) => `${context}${label} 방법으로는 시점 일치 자료에 ${missing}이 없어 이번 실행에서 ${run.symbol}의 방향 판단을 내리지 않습니다. 이는 약세 판단이나 반대표가 아니며, 해당 핵심 사실이 확보된 뒤에만 재평가합니다.`, available: (id) => `${id}을 시점 일치 출처에서 확보할 수 있게 됨` },
367
+ en: { none: "none", verdict: `${label} cannot evaluate ${run.symbol}: ${eligibility.reason}`, summary: (missing) => `The v3 typed-fact gate returned ${eligibility.status}; missing: ${missing}. No legacy prompt or narrative decision layer was called.`, fundContext: fundOrIndex ? `${run.symbol} is classified as ${instrument.asset_type}; this method must use dated holdings or aggregate index evidence rather than treating the instrument as an operating company. ` : "", statement: (missing, context) => `${context}Speaking through the ${label} method: I went looking for what my discipline runs on, and the point-in-time record lacks ${missing}. Without it I refuse to improvise a substitute, so I issue no directional view on ${run.symbol} in this run. That refusal is a judgment about the record, not about the asset -- it is neither bearish nor a vote against the asset. Hand me those method-critical facts from a dated source and I reassess on the spot.`, available: (id) => `${id} becomes available from a point-in-time source` },
368
+ zh: { none: "无", verdict: `${label}无法评估 ${run.symbol}:${eligibility.reason}`, summary: (missing) => `v3 typed-fact 闸门返回 ${eligibility.status};缺失:${missing}。系统未调用旧提示词或叙述决策层。`, fundContext: fundOrIndex ? `${run.symbol} 已识别为 ${instrument.asset_type};该方法必须通过带时点的持仓穿透或指数聚合证据使用,不能把它当成经营公司。` : "", statement: (missing, context) => `${context}按${label}方法发言:我先去找我的纪律赖以运转的材料,结果时点一致的资料缺少:${missing}。缺了它我拒绝拿代理数字凑合,所以本轮对 ${run.symbol} 不作方向判断。这个拒绝是对资料的判断,不是对资产的判断——这不是看空,也不是一张反对票。把这些带时点的方法关键事实交到我手上,我当场重新评估。`, available: (id) => `${id} 可从时点一致的来源取得` },
369
+ ja: { none: "なし", verdict: `${label}は ${run.symbol} を評価できません:${eligibility.reason}`, summary: (missing) => `v3 typed-fact ゲートは ${eligibility.status} を返しました。欠落:${missing}。旧プロンプトや叙述型の判断層は呼び出していません。`, fundContext: fundOrIndex ? `${run.symbol} は ${instrument.asset_type} に分類されており、事業会社として扱わず、基準日付き保有銘柄のルックスルーまたは指数集計証拠を用いる必要があります。` : "", statement: (missing, context) => `${context}${label}の方法として発言します。私の規律が拠って立つ材料を探しに行きましたが、時点整合した記録には ${missing} が欠けています。それなしに代理の数字で間に合わせることは拒みます。したがって今回は ${run.symbol} の方向判断を出しません。この拒否は記録に対する判断であって、資産に対する判断ではありません——弱気判断でも反対票でもありません。基準日付きの出典からこれらの事実が届き次第、その場で再評価します。`, available: (id) => `${id} が時点整合した出典から利用可能になる` },
370
+ ko: { none: "없음", verdict: `${label}은 ${run.symbol}을 평가할 수 없습니다: ${eligibility.reason}`, summary: (missing) => `v3 typed-fact 게이트가 ${eligibility.status}을 반환했습니다. 누락: ${missing}. 기존 프롬프트나 서술형 판단 계층은 호출하지 않았습니다.`, fundContext: fundOrIndex ? `${run.symbol}은 ${instrument.asset_type}로 분류되므로 영업회사처럼 취급하지 않고 기준일이 있는 보유 종목 룩스루 또는 지수 집계 증거를 사용해야 합니다. ` : "", statement: (missing, context) => `${context}${label} 방법으로 말합니다. 제 원칙이 딛고 서는 자료를 찾으러 갔지만, 시점 일치 기록에는 ${missing}이 없습니다. 그것 없이 대용 숫자로 때우는 것은 거부합니다. 따라서 이번 실행에서 ${run.symbol}의 방향 판단을 내리지 않습니다. 거부는 기록에 대한 판단이지 자산에 대한 판단이 아닙니다 — 약세 판단도 반대표도 아닙니다. 기준일 있는 출처에서 이 핵심 사실들을 건네주시면 자리에서 재평가하겠습니다.`, available: (id) => `${id}을 시점 일치 출처에서 확보할 수 있게 됨` },
371
371
  });
372
372
  const missing = eligibility.missing_required_fact_types.join(", ") || copy.none;
373
373
  const deterministicStatement = copy.statement(missing, copy.fundContext);
@@ -331,6 +331,8 @@ export function masterVoicePrompt(masterId, run, frozenOpinion) {
331
331
  [
332
332
  "Write the five `voice` fields in the first person, as the METHOD speaks -- \"I look for X, here the number is Y, so I would Z\".",
333
333
  "First person is the voice of the method, never a claim about what the living person currently thinks: write \"this standard asks for...\", never \"he now believes...\".",
334
+ "Write like the method's operator publishing a short opinion column, not like someone filling a form: each field is two to four complete sentences in the method's own characteristic register -- what it reaches for first, the standard it holds the number to, and why THIS number settles it. A reader should hear a person reasoning, not a checklist reporting.",
335
+ "The five voice fields are this worker's deliverable. Pace-tier compression applies to restatement and preamble, never to these fields: at any tier each stays at least two full sentences.",
334
336
  "Every figure you cite must already appear in the evidence or the frozen result, with its source ID. Cite the number, not an adjective about the number.",
335
337
  "`what_changes_my_mind` must name a threshold or an observation that would flip the reading, not a wish for more research.",
336
338
  "If the frozen stance is out_of_scope, say plainly and in the method's own voice which input it needs and why its absence is not a bearish view.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alphacouncil-agent",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "Multi-agent company, ETF and market-index research workflow for Codex & Claude Code: sourced evidence, method seats, bull/bear debate and portfolio-manager synthesis.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -145,5 +145,6 @@
145
145
  "docs/persona-v2-spec.md",
146
146
  "SECURITY.md",
147
147
  "CONTRIBUTING.md"
148
- ]
148
+ ],
149
+ "mcpName": "io.github.Zhao73/alphacouncil-agent"
149
150
  }