Merge pull request #5357 from deepseek-harness/turtle/config-inherited-compose

perf(settings): reuse composition for unoverridden entries
This commit is contained in:
imccyu authored and GitHub committed 2026-09-28 16:30:50 +08:00
commit 3366973eea
5 files changed
+111 -4

No files matched your search

+2 -2
View File
@@ -18,8 +18,8 @@
en: 1eedaa5d72b48177
zh: 39abc1d927a692d2
/deepseek-ai-dsh-config-editor/understand-the-implementation:
en: 972ac006df48ad85
zh: df8adddc40817877
en: b6ecd942daccc797
zh: 2f4637d725034f96
/deepseek-ai-dsh-config-editor/further-exploration:
en: 0c9e1d1401a865cc
zh: 6130d52636e84676
+2
View File
@@ -40,6 +40,8 @@ Use [settings](../../settings/settings/README.md) for forms restricted to live f
The [editor](src/index.ts) reconciles external changes before deriving a candidate, locks the profile manifest alongside other profile operations, and atomically replaces its config override. It preserves YAML comments and `!!js` expressions outside replaced values. A failed reconciliation restores the prior document and reloads the prior patches.
Configuration reads share one composition for entries without profile config overrides. Overridden entries are composed separately with only their own override removed; profile inserts and other entries' overrides remain effective. Returned configs are detached, and compositions are not cached between reads.
No invariant companion is published: the editor keeps no independent configuration projection. Loader and the persisted profile patch own configuration state.
</details>
+2
View File
@@ -40,6 +40,8 @@ kind: "package-reference"
[编辑器](src/index.ts) 在派生候选配置前应用外部更改,与其他 profile 操作共同锁定 profile manifest,并原子替换配置覆盖项。它保留替换值以外的 YAML 注释和 `!!js` 表达式。应用失败时恢复之前的文档并重新加载之前的 patch。
读取配置时,没有 profile config 覆盖项的条目共用一次组合结果。有覆盖项的条目分别组合,仅移除自身的覆盖项;profile 插入的条目和其他条目的覆盖项仍然生效。返回的配置为独立副本,组合结果不跨读取缓存。
此包不发布 invariant companion:编辑器不维护独立配置投影。Loader 和持久化的 profile patch 拥有配置状态。
</details>
+14 -2
View File
@@ -49,8 +49,20 @@ export class ConfigEditor extends Service {
configuration(): Array<{ entry: Entry; inherited: Record<string, unknown>; override: Record<string, unknown> }> {
const profile = this.ownerContext.profileContext
const loaded = loadProfileDirectory('dsh', profile.dir, profile.installAnchor)
return this.entries().map(entry => ({
entry, inherited: this.inherited(entry, loaded),
const entries = this.entries()
// An own config key can replace inherited config even when its value is undefined.
const overridden = new Set(loaded.patches.filter(patch => patch.insert === undefined && Object.hasOwn(patch, 'config')).map(patch => patch.id))
const composed = new Map<string, EntryOptions>()
if (entries.some(entry => !overridden.has(entry.options.id))) {
for (const row of flatten(composeEntries([...loaded.layers.map(layer => layer.patches), loaded.patches]))) {
if (!composed.has(row.id)) composed.set(row.id, row)
}
}
return entries.map(entry => ({
entry,
inherited: overridden.has(entry.options.id)
? this.inherited(entry, loaded)
: structuredClone((composed.get(entry.options.id)?.config ?? {}) as Record<string, unknown>),
override: structuredClone((loaded.patches.findLast(
row => row.id === entry.options.id && row.config !== undefined,
)?.config ?? {}) as Record<string, unknown>),
@@ -0,0 +1,91 @@
/** Shared profile composition preserves per-entry inheritance and detached results.
* Work-count spies require Vite-transformed source exports; native ESM namespaces are immutable.
*/
import { readFileSync, writeFileSync } from 'node:fs'
import { join } from 'node:path'
import { expect, it, vi } from 'vitest'
import * as appBoot from '@deepseek-ai/dsh-app-boot'
import { configurationFixture } from './configuration-fixture.ts'
it('shares composition for entries without config overrides while retaining group and insert inheritance', async () => {
const { ctx, profile, start } = await configurationFixture({ hmr: false })
await ctx.fiber.dispose()
writeFileSync(profile.patchPath, JSON.stringify([
{ id: 'first', config: { ordinary: 'fixed', count: 8 } },
{ id: 'first', config: { ordinary: 'fixed', count: 9 } },
{ id: 'second', disabled: false },
{ insert: [
{ id: 'inserted', name: 'cordis:probe', config: { ordinary: 'inserted', count: 3 } },
{ id: 'group', name: 'cordis:group', group: true, config: [
{ id: 'nested', name: 'cordis:probe', config: { ordinary: 'original', count: 4 } },
] },
] },
{ id: 'inserted', config: { ordinary: 'inserted', count: 7 } },
{ id: 'group', config: [
{ id: 'nested', name: 'cordis:probe', config: { ordinary: 'replacement', count: 6 } },
] },
]))
const restored = await start()
const compose = vi.spyOn(appBoot, 'composeEntries')
try {
const rows = restored.configEditor.configuration()
const inherited = Object.fromEntries(rows.map(row => [row.entry.options.id, row.inherited]))
expect(inherited).toMatchObject({
first: { ordinary: 'fixed', token: 'private' },
second: { ordinary: 'second' },
inserted: { ordinary: 'inserted', count: 3 },
nested: { ordinary: 'replacement', count: 6 },
group: [{ id: 'nested', name: 'cordis:probe', config: { ordinary: 'original', count: 4 } }],
})
expect(inherited['first']).not.toHaveProperty('count')
expect(compose).toHaveBeenCalledTimes(4)
const nested = rows.find(row => row.entry.options.id === 'nested')!
nested.inherited['ordinary'] = 'mutated'
expect(nested.entry.options.config).toMatchObject({ ordinary: 'replacement' })
expect(restored.configEditor.configuration().find(row => row.entry.options.id === 'nested')!.inherited)
.toEqual({ ordinary: 'replacement', count: 6 })
} finally {
compose.mockRestore()
}
})
it('recomposes unoverridden entries after bundle changes and returns empty configs when absent', async () => {
const { ctx, profile } = await configurationFixture({ hmr: false })
const read = () => ctx.configEditor.configuration()
const before = read()
expect(before.find(row => row.entry.options.id === 'config-editor')!.inherited).toEqual({})
const bundlePath = join(profile.dir, 'node_modules', 'test-bundle', 'cordis.patch.yml')
const patches = JSON.parse(readFileSync(bundlePath, 'utf8')) as Array<{ insert: Array<{ id: string; config?: object }> }>
patches[0]!.insert.find(row => row.id === 'second')!.config = { ordinary: 'new bundle value' }
writeFileSync(bundlePath, JSON.stringify(patches))
expect(read().find(row => row.entry.options.id === 'second')!.inherited).toEqual({ ordinary: 'new bundle value' })
expect(before.find(row => row.entry.options.id === 'second')!.inherited).toEqual({ ordinary: 'second' })
patches[0]!.insert.push({ id: 'second', config: { ordinary: 'duplicate' } })
writeFileSync(bundlePath, JSON.stringify(patches))
expect(read().find(row => row.entry.options.id === 'second')!.inherited).toEqual({ ordinary: 'new bundle value' })
})
it.each([0, 13, 190])('bounds composition work for 190 entries with %i config overrides', async (overrideCount) => {
const { ctx, profile, start } = await configurationFixture({ hmr: false })
await ctx.fiber.dispose()
const bundlePath = join(profile.dir, 'node_modules', 'test-bundle', 'cordis.patch.yml')
const patches = JSON.parse(readFileSync(bundlePath, 'utf8')) as Array<{ insert: Array<{ id: string; config?: object }> }>
const entries = Array.from({ length: 185 }, (_, index) => ({
id: `generated-${index}`, name: 'cordis:probe', config: { ordinary: `value-${index}` },
}))
patches[0]!.insert.push(...entries)
writeFileSync(bundlePath, JSON.stringify(patches))
writeFileSync(profile.patchPath, JSON.stringify(patches[0]!.insert.slice(0, overrideCount).map(entry => ({
id: entry.id, config: entry.config ?? {},
}))))
const restored = await start()
const compose = vi.spyOn(appBoot, 'composeEntries')
try {
const rows = restored.configEditor.configuration()
expect(rows).toHaveLength(190)
expect(rows.find(row => row.entry.options.id === 'generated-0')!.inherited).toEqual({ ordinary: 'value-0' })
expect(compose).toHaveBeenCalledTimes(overrideCount + Number(overrideCount < rows.length))
} finally {
compose.mockRestore()
}
})