Window consultation sends its two chart requests together (issue #128, BUG-1473)
executeWindowConsultation awaited /api/declared_window_chart before sending /api/rectification/v5/range_reading, which does not depend on it. Both now go out at once; a failed range reading still only drops the minute-sensitive themes. Two 150 ms stubs: ~150 ms total instead of ~300 ms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ad801a5db7
commit
ea7dd95757
@@ -1,5 +1,10 @@
|
||||
# 印度占星 Skill 更新日志
|
||||
|
||||
## 2026-10-28 — 只知道出生时段时,咨询出字更快
|
||||
|
||||
- 只填了出生时段(没有精确到分钟)的人来咨询时,后台两次计算改成同时进行,每轮约快 0.3~1 秒。回答内容不变。
|
||||
- Skill 版本不变(BUG-1473,issue #128)。
|
||||
|
||||
## 2026-10-28 — 回答出字时页面不再整页重画
|
||||
|
||||
- 回答逐字出来时,只有回答那一块在更新;顶栏、输入框和右侧本命盘不再每一帧跟着重画(以前最多每秒 60 次)。长回答时电脑更省力,滚动和点按更跟手。看到的内容不变。
|
||||
|
||||
@@ -20096,3 +20096,18 @@
|
||||
- 关联:BUG-1329(侧栏每帧重注册)、BUG-1130。
|
||||
- 复发自:无
|
||||
- 修复版本:分支 `codex/home-stream-rerender-20261028`。
|
||||
|
||||
## BUG-1473 | 按出生时段咨询时,窗口排盘和时段读数排队串行
|
||||
|
||||
- 状态:resolved(代码 + 回归测试;待部署)
|
||||
- 首次发现 / 最近更新:2026-10-28 / 2026-10-28(issue #118 代码体检第 11 条 → #128)
|
||||
- 影响面:只知道出生时段(没有精确出生分钟)的咨询;`frontend/src/mastra/consultation-tools.ts` `executeWindowConsultation`。
|
||||
- 现象:这类咨询每轮在出字前多等一段:先等 `/api/declared_window_chart` 回来,再发 `/api/rectification/v5/range_reading`。估每轮 0.3~1 秒。
|
||||
- 触发条件:任何按出生时段(declared birth window)走的咨询轮。
|
||||
- 根因:两个请求互不依赖,代码却先 `await` 第一个再发第二个。
|
||||
- 修复:时段读数先发出、窗口排盘随后发出,两者同时进行,再一起等结果。时段读数失败仍只是没有「分钟敏感主题」,与改前相同;窗口排盘失败时整轮照旧失败,只是此时时段读数已经发出(结果丢弃)。
|
||||
- 验证:`frontend/tests/consultation-agentic-runtime.test.ts` 新增两条:两个桩各延时 150 ms,改后总耗时 <260 ms(改前约 300 ms,改前代码上该测试失败),且窗口排盘返回前时段读数已开始;`minuteSensitiveThemes` 与改前一致。时段读数抛错时照常完成、不带分钟敏感主题。同文件既有窗口咨询测试(BUG-957 三条)全过。tsc 0、lint 0。
|
||||
- 防复发:上述测试。互不依赖的后端请求同时发。
|
||||
- 关联:BUG-957(窗口咨询预计算与缓存)。
|
||||
- 复发自:无
|
||||
- 修复版本:分支 `codex/window-consult-parallel-20261028`。
|
||||
|
||||
@@ -1620,12 +1620,9 @@ async function executeWindowConsultation(
|
||||
label: "正在比较声明出生窗口内的稳定层",
|
||||
},
|
||||
});
|
||||
const packet = await (ctx.fetchWindowChart ?? fetchDeclaredWindowChart)({
|
||||
window: ctx.declaredWindow,
|
||||
signal: context.abortSignal ?? ctx.abortSignal,
|
||||
});
|
||||
let minuteSensitiveThemes: string[] = [];
|
||||
try {
|
||||
// The range reading does not depend on the window chart, so both go out at once
|
||||
// (issue #128). A failed reading still only drops the minute-sensitive themes.
|
||||
const sensitiveThemes = (async () => {
|
||||
const reading = await (ctx.runRangeReading ?? runV9RangeReading)({
|
||||
baselineBirthSnapshot: {
|
||||
birth_date: ctx.declaredWindow.truth.birthDate,
|
||||
@@ -1640,10 +1637,13 @@ async function executeWindowConsultation(
|
||||
},
|
||||
birthTimeAccuracy: "approximate",
|
||||
});
|
||||
minuteSensitiveThemes = [...(reading?.sensitiveThemes ?? [])];
|
||||
} catch {
|
||||
minuteSensitiveThemes = [];
|
||||
}
|
||||
return [...(reading?.sensitiveThemes ?? [])];
|
||||
})().catch((): string[] => []);
|
||||
const packet = await (ctx.fetchWindowChart ?? fetchDeclaredWindowChart)({
|
||||
window: ctx.declaredWindow,
|
||||
signal: context.abortSignal ?? ctx.abortSignal,
|
||||
});
|
||||
const minuteSensitiveThemes = await sensitiveThemes;
|
||||
const varyingLagna = Array.isArray(packet.varying_layers.ascendant_signs)
|
||||
&& packet.varying_layers.ascendant_signs.length > 1;
|
||||
ctx.state.workflowReceipt = {
|
||||
|
||||
@@ -1636,7 +1636,12 @@ function windowPacket() {
|
||||
};
|
||||
}
|
||||
|
||||
function makeWindowCtx(options: { fetchWindowChart?: () => Promise<ReturnType<typeof windowPacket>> } = {}) {
|
||||
function makeWindowCtx(options: {
|
||||
fetchWindowChart?: () => Promise<ReturnType<typeof windowPacket>>;
|
||||
runRangeReading?: () => Promise<{
|
||||
stableThemes: string[]; sensitiveThemes: string[]; claimBoundary: null; themeSensitivity: Record<string, unknown>; window: null;
|
||||
}>;
|
||||
} = {}) {
|
||||
const state = createConsultationRuntimeState();
|
||||
const ctx = createWindowConsultationAgentContext({
|
||||
userId: "u",
|
||||
@@ -1646,9 +1651,9 @@ function makeWindowCtx(options: { fetchWindowChart?: () => Promise<ReturnType<ty
|
||||
declaredWindow: declaredWindowFixture,
|
||||
state,
|
||||
fetchWindowChart: options.fetchWindowChart ?? (async () => windowPacket()),
|
||||
runRangeReading: async () => {
|
||||
runRangeReading: options.runRangeReading ?? (async () => {
|
||||
throw new Error("range-reading-unused-in-this-test");
|
||||
},
|
||||
}),
|
||||
});
|
||||
return { ctx, state, tools: createWindowConsultationTools(ctx) };
|
||||
}
|
||||
@@ -1730,6 +1735,41 @@ test("window precompute and a later tool call share one cache (BUG-957)", async
|
||||
assert.deepEqual(first, second);
|
||||
});
|
||||
|
||||
test("the window chart and the range reading go out together (issue #128)", async () => {
|
||||
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
let rangeStarted = false;
|
||||
let rangeStartedBeforeChartReturned = false;
|
||||
const { ctx, state } = makeWindowCtx({
|
||||
fetchWindowChart: async () => {
|
||||
await delay(150);
|
||||
rangeStartedBeforeChartReturned = rangeStarted;
|
||||
return windowPacket();
|
||||
},
|
||||
runRangeReading: async () => {
|
||||
rangeStarted = true;
|
||||
await delay(150);
|
||||
return { stableThemes: [], sensitiveThemes: ["career"], claimBoundary: null, themeSensitivity: {}, window: null };
|
||||
},
|
||||
});
|
||||
const startedAt = Date.now();
|
||||
await precomputeWindowConsultation(ctx, { question: "事业如何" });
|
||||
const elapsed = Date.now() - startedAt;
|
||||
assert.equal(rangeStartedBeforeChartReturned, true);
|
||||
// Serial was 300 ms; together it is about the longer of the two.
|
||||
assert.ok(elapsed < 260, `took ${elapsed} ms`);
|
||||
assert.deepEqual(state.workflowReceipt?.minuteSensitiveThemes, ["career"]);
|
||||
assert.equal(state.consultationToolCompleted, true);
|
||||
});
|
||||
|
||||
test("a failed range reading still only drops the minute-sensitive themes (issue #128)", async () => {
|
||||
const { ctx, state } = makeWindowCtx({
|
||||
runRangeReading: async () => { throw new Error("range_unavailable"); },
|
||||
});
|
||||
await precomputeWindowConsultation(ctx, { question: "事业如何" });
|
||||
assert.equal(state.consultationToolCompleted, true);
|
||||
assert.equal(state.workflowReceipt?.minuteSensitiveThemes, undefined);
|
||||
});
|
||||
|
||||
test("window precompute failure still degrades when the model writes without a tool (BUG-957)", async () => {
|
||||
const { ctx, state } = makeWindowCtx({
|
||||
fetchWindowChart: async () => {
|
||||
|
||||
Reference in New Issue
Block a user