mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-08-29 04:26:38 +00:00
Merge remote-tracking branch 'origin/master' into dshw/pr-deepseek-harness-deepseek-harness-2731
# Conflicts: # packages/util/brand/README.i18n.yaml # packages/util/brand/README.md # packages/util/brand/README.zh.md
This commit is contained in:
@@ -4,6 +4,7 @@ import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
checkExperimentalDependencyIsolation,
|
||||
checkExperimentalManifest,
|
||||
expectedDshPackageFiles,
|
||||
type WorkspaceManifest,
|
||||
} from './check-workspace-constraints.ts'
|
||||
|
||||
@@ -74,3 +75,17 @@ describe('experimental workspace constraints', () => {
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('package payload constraints', () => {
|
||||
it('includes a declared profile patch without a package-name allowlist', () => {
|
||||
expect(expectedDshPackageFiles({
|
||||
name: '@deepseek-ai/dsh-private-profile',
|
||||
dsh: { bundle: { patch: './cordis.patch.yml' } },
|
||||
})).toEqual([
|
||||
'lib/index.js',
|
||||
'lib/invariant.js',
|
||||
'cordis.patch.yml',
|
||||
'lib/types/**/*.d.ts',
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -174,7 +174,7 @@ function sameStringList(actual: readonly string[] | undefined, expected: readonl
|
||||
return !!actual && actual.length === expected.length && actual.every((value, index) => value === expected[index])
|
||||
}
|
||||
|
||||
function expectedDshPackageFiles(manifest: PackageManifest): readonly string[] {
|
||||
export function expectedDshPackageFiles(manifest: PackageManifest): readonly string[] {
|
||||
const declaredPatch = manifest.dsh?.bundle?.patch
|
||||
const bundleFiles = declaredPatch === undefined ? [] : [declaredPatch.replace(/^\.\//, '')]
|
||||
const extras = [
|
||||
|
||||
@@ -39,4 +39,20 @@ export const coverageExemptHeavySuites: readonly CoverageExemptSuite[] = [
|
||||
{ filter: 'scripts/oxlint-contract.spec.ts', exclude: 'scripts/oxlint-contract.spec.ts' },
|
||||
{ filter: 'scripts/change-scope.spec.ts', exclude: 'scripts/change-scope.spec.ts' },
|
||||
{ filter: 'scripts/translation-pairing-merge.spec.ts', exclude: 'scripts/translation-pairing-merge.spec.ts' },
|
||||
// Spawns the full-corpus transform gate in a child process (Node's ESM
|
||||
// loader is its oracle), so no measured file executes in-process; the
|
||||
// package src is threshold-excluded in vitest.config.ts. A single
|
||||
// 900s-budget case; running it inside an instrumented partition exceeds
|
||||
// the Windows partition budget under load.
|
||||
{
|
||||
filter: 'packages/experimental/webworker-runtime/tests/compile/transform-corpus.spec.ts',
|
||||
exclude: 'packages/experimental/webworker-runtime/tests/compile/transform-corpus.spec.ts',
|
||||
},
|
||||
// Built-artifact proof. Packer/runtime src is threshold-excluded, and the
|
||||
// native Windows aggregate makes this uninstrumented gate wait for build so
|
||||
// the suite never observes a partially emitted workspace closure.
|
||||
{
|
||||
filter: 'packages/experimental/webworker-packer/tests/image-loadable.spec.ts',
|
||||
exclude: 'packages/experimental/webworker-packer/tests/image-loadable.spec.ts',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
/**
|
||||
* Quick comprehensive documentation-standard tests: the reference example
|
||||
* stays valid, the consolidated `dsh-doc` skill carries no stale copied
|
||||
* website values or prototype-era language, and the kind system maps each
|
||||
* label to exactly one skill template. These run in `pnpm run test` and
|
||||
* `pnpm run test:docs` to guard the standard between heavier corpus gates.
|
||||
* @module scripts/doc-standard.spec
|
||||
*/
|
||||
|
||||
import { existsSync, globSync, readFileSync } from 'node:fs'
|
||||
import { resolve, sep } from 'node:path'
|
||||
import { load } from 'js-yaml'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
const PACKAGE_README_GLOBS = [
|
||||
'packages/README.md',
|
||||
'packages/README.zh.md',
|
||||
'packages/*/README.md',
|
||||
'packages/*/README.zh.md',
|
||||
'packages/*/*/README.md',
|
||||
'packages/*/*/README.zh.md',
|
||||
] as const
|
||||
|
||||
function packageReadmes(): string[] {
|
||||
return PACKAGE_README_GLOBS
|
||||
.flatMap(pattern => globSync(pattern, { cwd: root, exclude: ['**/node_modules/**'] }))
|
||||
.map(file => file.replaceAll('\\', '/'))
|
||||
.sort()
|
||||
}
|
||||
|
||||
/**
|
||||
* The kind system: each label maps to exactly one template in the dsh-doc
|
||||
* skill. The check derives the expected kind from the same mechanical facts
|
||||
* the skill documents; a kind without a template, a template without a kind,
|
||||
* or a document whose kind does not match its position fails here.
|
||||
*/
|
||||
const KIND_TEMPLATES: Readonly<Record<string, string>> = {
|
||||
'package-group': '.agents/skills/dsh-doc/templates/package-group.md',
|
||||
'package-reference': '.agents/skills/dsh-doc/templates/package-reference.md',
|
||||
'package-library': '.agents/skills/dsh-doc/templates/package-library.md',
|
||||
'package-bundle': '.agents/skills/dsh-doc/templates/package-bundle.md',
|
||||
}
|
||||
|
||||
/**
|
||||
* Audited packages whose entry is a plain module API rather than a Cordis
|
||||
* plugin (`apply` export or a default service export) or an installable
|
||||
* bundle (`dsh.bundle.patch`). Each entry names why the package is a
|
||||
* library; the check re-derives the entry shape so a stale entry fails loud.
|
||||
*/
|
||||
const PACKAGE_LIBRARIES: Readonly<Record<string, string>> = {
|
||||
'packages/boot/app-boot': 'Boot library the app bins import; plain helper exports.',
|
||||
'packages/boot/cmdline': 'Command-line library the app bins import; plain module exports.',
|
||||
'packages/client/store': 'Browser-side state primitives; plain function/type exports.',
|
||||
'packages/client/ui-primitives': 'Browser-side UI component library; plain component exports.',
|
||||
'packages/client/ui-slots': 'Browser-side slot-map declarations; plain type exports.',
|
||||
'packages/client/web': 'Browser application boot library; exports the app entry and static module table.',
|
||||
'packages/code-runtime/code-runtime-python': 'Host-side protocol library for the CPython subprocess runtime.',
|
||||
'packages/core/scope': 'Scoped-context primitives; exports functions and types without a plugin entry.',
|
||||
'packages/experimental/webworker-packer': 'Build-time VFS image packer and command library.',
|
||||
'packages/experimental/webworker-runtime': 'Browser worker runtime library with explicit host entry points.',
|
||||
'packages/hooks/hook-protocol': 'Shared wire-protocol library between the hook bridges.',
|
||||
'packages/identity/anonymous-user-id': 'Harness-home identity helper with no plugin registration.',
|
||||
'packages/sandbox/sandbox-windows-acl': 'Windows ACL sandbox library consumed by sandbox-local.',
|
||||
'packages/sdk/client': 'Client-process library; the spawned runtime owns plugin behavior.',
|
||||
'packages/sdk/protocol': 'Wire-protocol library with type declarations only.',
|
||||
'packages/session/session-telemetry': 'Telemetry Service Definition and capture library; providers mount the backend.',
|
||||
'packages/session/session-title-llm': 'Shared LLM title-provider registration and request policy.',
|
||||
'packages/subagent/subagent-in-process-driver': 'Shared one-shot child-agent driver used by provider plugins.',
|
||||
'packages/subprocess/win32-process': 'Low-level Win32 process and Job Object primitives.',
|
||||
'packages/test-support/session-snapshot': 'Test infrastructure; mounts nothing into a product composition.',
|
||||
'packages/test-support/agent-loop-testkit': 'Test helper library; mounts nothing into a product composition.',
|
||||
'packages/test-support/client-runtime': 'Browser-side test infrastructure.',
|
||||
'packages/test-support/llm-mock-server': 'Test server library; substitutes provider wire behavior.',
|
||||
'packages/test-support/loader-smoke': 'Test harness library; mounts nothing into a product composition.',
|
||||
'packages/typert/generator': 'Build-time generator run outside any agent runtime.',
|
||||
'packages/typert/protocol': 'Compiler-independent protocol declarations.',
|
||||
'packages/util/atomic-write': 'Zero-dependency filesystem write utility.',
|
||||
'packages/util/brand': 'Type-only branding primitive erased at compile time.',
|
||||
'packages/util/crypto': 'Zero-dependency identifier minting utility.',
|
||||
'packages/util/home-paths': 'Zero-dependency harness-home path resolver.',
|
||||
'packages/util/launch-environment': 'Zero-dependency environment resolver.',
|
||||
'packages/util/native-command': 'Host-side subprocess runner utility.',
|
||||
'packages/util/output-retention': 'Zero-dependency retention utility.',
|
||||
'packages/util/timeout': 'Zero-dependency timeout utility.',
|
||||
'packages/util/workspace-path': 'Zero-dependency Workspace path formatter.',
|
||||
}
|
||||
|
||||
function readFrontmatter(file: string): Record<string, unknown> {
|
||||
const source = readFileSync(resolve(root, file), 'utf8')
|
||||
const match = /^---\n([\s\S]*?)\n---\n/u.exec(source)
|
||||
expect(match, `${file}: YAML frontmatter`).not.toBeNull()
|
||||
const metadata = load(match?.[1] ?? '')
|
||||
expect(metadata, `${file}: frontmatter object`).toBeTypeOf('object')
|
||||
expect(Array.isArray(metadata), `${file}: frontmatter object`).toBe(false)
|
||||
return metadata as Record<string, unknown>
|
||||
}
|
||||
|
||||
function packageDir(file: string): string {
|
||||
return file.replaceAll('\\', '/').replace(/\/README\.zh\.md$/, '').replace(/\/README\.md$/, '')
|
||||
}
|
||||
|
||||
/** Whether the package manifest declares `dsh.bundle.patch`. */
|
||||
function declaresBundle(dir: string): boolean {
|
||||
const manifest = resolve(root, dir, 'package.json')
|
||||
if (!existsSync(manifest)) return false
|
||||
const metadata = JSON.parse(readFileSync(manifest, 'utf8')) as { dsh?: { bundle?: { patch?: string } } }
|
||||
return metadata.dsh?.bundle?.patch !== undefined
|
||||
}
|
||||
|
||||
/** The expected kind for one package README, from the facts the skill documents. */
|
||||
function expectedKind(file: string): string {
|
||||
const normalized = file.replaceAll('\\', '/')
|
||||
if (normalized.split('/').length <= 3) return 'package-group'
|
||||
const dir = packageDir(normalized)
|
||||
if (declaresBundle(dir)) return 'package-bundle'
|
||||
if (Object.hasOwn(PACKAGE_LIBRARIES, dir)) return 'package-library'
|
||||
return 'package-reference'
|
||||
}
|
||||
|
||||
function packageReadmeMetadataErrors(file: string, metadata: Record<string, unknown>): string[] {
|
||||
const errors: string[] = []
|
||||
if (metadata.kind !== expectedKind(file)) errors.push(`kind must be ${expectedKind(file)}`)
|
||||
if (typeof metadata.description !== 'string' || metadata.description.trim() === '') {
|
||||
errors.push('description must be a non-empty string')
|
||||
}
|
||||
for (const field of ['name', 'audience', 'tags', 'i18n']) {
|
||||
if (field in metadata) errors.push(`${field} is redundant or has no governed consumer`)
|
||||
}
|
||||
return errors
|
||||
}
|
||||
|
||||
function packageReadmeStructureErrors(file: string, source: string): string[] {
|
||||
const chinese = file.endsWith('.zh.md')
|
||||
const required = chinese
|
||||
? [[/^## 概述$/m, '概述'], [/^## 目录$/m, '目录'], [/^#{2,3} 开发备注$/m, '开发备注']] as const
|
||||
: [[/^## Summary$/m, 'Summary'], [/^## Table of Contents$/m, 'Table of Contents'], [/^#{2,3} Dev Note$/m, 'Dev Note']] as const
|
||||
return required.flatMap(([pattern, label]) => pattern.test(source) ? [] : [`missing ${label}`])
|
||||
}
|
||||
|
||||
describe('dsh-doc skill consolidation', () => {
|
||||
it('carries no prototype-era language', () => {
|
||||
const files = [
|
||||
'.agents/skills/dsh-doc/SKILL.md',
|
||||
'.agents/skills/dsh-doc/references/metadata-links-i18n.md',
|
||||
'.agents/skills/dsh-doc/references/structure-hierarchy.md',
|
||||
'.agents/skills/dsh-doc/references/style.md',
|
||||
'.agents/skills/dsh-doc/references/review.md',
|
||||
'.agents/skills/dsh-doc/references/website-sync.md',
|
||||
]
|
||||
for (const file of files) {
|
||||
const source = readFileSync(resolve(root, file), 'utf8')
|
||||
expect(source, file).not.toMatch(/\bprototype\b/i)
|
||||
}
|
||||
})
|
||||
|
||||
it('copies no stale website sidebar or section-owner values', () => {
|
||||
const source = readFileSync(resolve(root, '.agents/skills/dsh-doc/references/website-sync.md'), 'utf8')
|
||||
expect(source).not.toContain('en-docs')
|
||||
expect(source).not.toContain('sectionOrder')
|
||||
})
|
||||
|
||||
it('keeps the reference example linked from the skill', () => {
|
||||
const skill = readFileSync(resolve(root, '.agents/skills/dsh-doc/SKILL.md'), 'utf8')
|
||||
expect(skill).toContain('session-persistence-sqlite/README.md')
|
||||
expect(skill).toContain('session-persistence-sqlite/README.zh.md')
|
||||
})
|
||||
|
||||
it('defines controlled English as a precision-preserving review discipline', () => {
|
||||
const skill = readFileSync(resolve(root, '.agents/skills/dsh-doc/SKILL.md'), 'utf8')
|
||||
const style = readFileSync(resolve(root, '.agents/skills/dsh-doc/references/style.md'), 'utf8')
|
||||
expect(skill).toContain('references/style.md#controlled-technical-english')
|
||||
expect(style).toContain('not certified ASD-STE100 compliance')
|
||||
expect(style).toContain('review prompts, not mechanical gates')
|
||||
expect(style).toContain('Never remove or strengthen `must`, `may`, `never`')
|
||||
})
|
||||
|
||||
it('maps every kind label to exactly one skill template that exists', () => {
|
||||
const templateFiles = globSync('.agents/skills/dsh-doc/templates/*.md', { cwd: root }).map(path => path.split(sep).join('/')).sort()
|
||||
const registered = Object.values(KIND_TEMPLATES).sort()
|
||||
expect(templateFiles).toEqual(registered)
|
||||
for (const [kind, template] of Object.entries(KIND_TEMPLATES)) {
|
||||
expect(existsSync(resolve(root, template)), `${kind}: template ${template}`).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('maps package README kinds to their documentation standards', () => {
|
||||
const files = packageReadmes()
|
||||
expect(files.length).toBeGreaterThan(0)
|
||||
|
||||
for (const file of files) {
|
||||
const metadata = readFrontmatter(file)
|
||||
expect(packageReadmeMetadataErrors(file, metadata), file).toEqual([])
|
||||
}
|
||||
})
|
||||
|
||||
it('keeps the audited library registry accurate: every entry has a plain module entry and no bundle declaration', () => {
|
||||
for (const [dir, reason] of Object.entries(PACKAGE_LIBRARIES)) {
|
||||
expect(reason.trim().length, `${dir}: library justification`).toBeGreaterThan(0)
|
||||
expect(declaresBundle(dir), `${dir}: a bundle declaration makes this package-bundle, not a library`).toBe(false)
|
||||
const entry = resolve(root, dir, 'src/index.ts')
|
||||
expect(existsSync(entry), `${dir}: library entry`).toBe(true)
|
||||
const source = readFileSync(entry, 'utf8')
|
||||
expect(source, `${dir}: entry must be a plain module, not a plugin`).not.toMatch(/export (?:default|\{[^}]*default[^}]*\} from)/u)
|
||||
expect(source, `${dir}: entry must be a plain module, not a plugin`).not.toMatch(/export (?:async )?(?:function|const) apply\b/u)
|
||||
}
|
||||
})
|
||||
|
||||
it('keeps every package README on the summary, contents, and Dev Note skeleton', () => {
|
||||
for (const file of packageReadmes().filter(file => file.split('/').length === 4)) {
|
||||
const source = readFileSync(resolve(root, file), 'utf8')
|
||||
expect(packageReadmeStructureErrors(file, source), file).toEqual([])
|
||||
}
|
||||
})
|
||||
|
||||
it('rejects redundant fields and a kind that does not match the README position', () => {
|
||||
expect(packageReadmeMetadataErrors('packages/example/README.md', {
|
||||
description: 'Example group.',
|
||||
kind: 'package-reference',
|
||||
name: 'example',
|
||||
audience: ['developer'],
|
||||
tags: ['example'],
|
||||
i18n: { counterpart: 'README.zh.md' },
|
||||
})).toEqual([
|
||||
'kind must be package-group',
|
||||
'name is redundant or has no governed consumer',
|
||||
'audience is redundant or has no governed consumer',
|
||||
'tags is redundant or has no governed consumer',
|
||||
'i18n is redundant or has no governed consumer',
|
||||
])
|
||||
expect(packageReadmeMetadataErrors('packages\\example\\package\\README.md', {
|
||||
description: 'Example package.',
|
||||
kind: 'package-reference',
|
||||
})).toEqual([])
|
||||
})
|
||||
|
||||
it('rejects README-local i18n metadata', () => {
|
||||
expect(packageReadmeMetadataErrors('packages\\example\\package\\README.md', {
|
||||
description: 'Example package.',
|
||||
kind: 'package-reference',
|
||||
i18n: {
|
||||
'counterpart': 'packages/example/package/README.zh.md',
|
||||
'line-aligned': true,
|
||||
},
|
||||
})).toEqual([
|
||||
'i18n is redundant or has no governed consumer',
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('reference-example README pair', () => {
|
||||
const dir = 'packages/session/session-persistence-sqlite'
|
||||
|
||||
it('keeps exact English/Chinese physical line alignment', () => {
|
||||
const sourceLines = readFileSync(resolve(root, dir, 'README.md'), 'utf8').split('\n').length
|
||||
const zhLines = readFileSync(resolve(root, dir, 'README.zh.md'), 'utf8').split('\n').length
|
||||
expect(sourceLines).toBe(zhLines)
|
||||
})
|
||||
|
||||
it('keeps the sidecar consistency record present', () => {
|
||||
const sidecar = readFileSync(resolve(root, dir, 'README.i18n.yaml'), 'utf8')
|
||||
expect(sidecar).toMatch(/^README\.md: [0-9a-f]{40}$/m)
|
||||
expect(sidecar).toMatch(/^README\.zh\.md: [0-9a-f]{40}$/m)
|
||||
})
|
||||
})
|
||||
@@ -758,7 +758,7 @@ export const CORDIS_CATALOG_POLICY: CordisCatalogPolicy = {
|
||||
{ name: 'ctx.effect', summary: 'Register a disposable side effect tied to the fiber.', source: 'vendor/cordis/src/fiber.ts:9' },
|
||||
{ name: 'ctx.get / ctx.set / ctx.provide / ctx.accessor / ctx.mixin', summary: 'Low-level service-store access and binding.', source: 'vendor/cordis/src/reflect.ts:7' },
|
||||
{ name: 'ctx.extend / ctx.isolate / ctx.intercept', summary: 'Derive a child context (scoped services / isolation / interception).', source: 'vendor/cordis/src/context.ts:42' },
|
||||
{ name: 'ctx.root / ctx.scope / ctx.fiber / ctx.registry / ctx.reflect / ctx.events / ctx.logger', summary: 'Ambient handles onto the running context graph.', source: 'vendor/cordis/src/context.ts:16' },
|
||||
{ name: 'ctx.root / ctx.fiber / ctx.registry / ctx.reflect / ctx.events / ctx.logger', summary: 'Ambient handles onto the running context graph.', source: 'vendor/cordis/src/context.ts:16' },
|
||||
{ name: 'ctx.timer (+ interval / timeout / throttle / debounce)', summary: 'Disposable timer helpers. The `timer` key is provided at runtime; the four supported helpers are mixed onto ctx directly (declared via Pick).', source: 'vendor/timer/src/index.ts:4' },
|
||||
{ name: 'ctx.loader', summary: 'The config Loader that booted the app (present under the loader).', source: 'vendor/loader/src/index.ts:30' },
|
||||
{ name: 'ctx.hmr', summary: 'The hot-module-reload watcher (present under the hmr plugin).', source: 'vendor/hmr/src/index.ts:15' },
|
||||
|
||||
@@ -14,7 +14,7 @@ const CLIENT_SERVICES: Readonly<Record<string, readonly string[]>> = {
|
||||
locale: ['getLocale', 'getSnapshot', 'subscribe', 'setLocale', 'addLanguage', 'register', 'bind'],
|
||||
sessions: ['open', 'openSubagent', 'setSubagentCatalogOpen', 'refreshSubagents', 'search', 'fork', 'scope', 'binding'],
|
||||
slots: ['register', 'inject'],
|
||||
theme: ['getTheme', 'setTheme', 'register', 'overrideTokens'],
|
||||
theme: ['getTheme', 'setTheme', 'setFontSize', 'register', 'overrideTokens'],
|
||||
uiWorkspace: [
|
||||
'connectWorkspace', 'startSession', 'archiveSession', 'pickDirectory', 'listDirectory',
|
||||
'createDirectory', 'openPath',
|
||||
|
||||
+23
-23
@@ -104,7 +104,7 @@ const SERVICE_ROLES: ServiceRole[] = [
|
||||
title: 'Durable binary attachment storage',
|
||||
mode: 'seam',
|
||||
implementations: ['attachment-local'],
|
||||
consumers: ['host-runtime', 'llm-pi-ai'],
|
||||
consumers: ['api-session-controller', 'host-apiproxy', 'tool-fs', 'llm-pi-ai', 'llm-deepseek'],
|
||||
note: 'The host commits accepted images before session events; provider adapters resolve authorized durable references into provider-native content.',
|
||||
},
|
||||
{
|
||||
@@ -146,7 +146,7 @@ const SERVICE_ROLES: ServiceRole[] = [
|
||||
pkg: 'session',
|
||||
title: 'In-memory session store',
|
||||
mode: 'core',
|
||||
consumers: ['agent-loop', 'agent', 'session-persistence', 'session-query', 'session-query-sqlite', 'subagent-inprocess', 'invariants', 'message-feedback'],
|
||||
consumers: ['agent-loop', 'agent', 'session-persistence', 'session-query', 'session-query-sqlite', 'subagent-in-process-driver', 'invariants', 'message-feedback'],
|
||||
note: 'Owns append-only Session instances and emits the durable session event feed.',
|
||||
},
|
||||
{
|
||||
@@ -154,7 +154,7 @@ const SERVICE_ROLES: ServiceRole[] = [
|
||||
pkg: 'api-session-controller',
|
||||
title: 'Host Session Remote controller',
|
||||
mode: 'core',
|
||||
consumers: ['apiproxy'],
|
||||
consumers: ['host-apiproxy'],
|
||||
note: 'Owns Session commands, cold reads, durable-event following, live control state, and Agent activation policy; apiProxy reuses its inspection and Agent-resolution operations for Session-aware domains.',
|
||||
},
|
||||
{
|
||||
@@ -202,7 +202,7 @@ const SERVICE_ROLES: ServiceRole[] = [
|
||||
title: 'User-settings seam',
|
||||
mode: 'seam',
|
||||
implementations: ['settings-file'],
|
||||
consumers: ['llm-deepseek', 'llm-pi-ai', 'apiproxy'],
|
||||
consumers: ['llm-deepseek', 'llm-pi-ai', 'host-apiproxy'],
|
||||
note: 'Plugins register namespace schemas and resolve layered values; providers store the raw document. The LLM adapters register their entry config as the composition base under the user section; the web gateway serves redacted layered descriptors and writes the user layer.',
|
||||
},
|
||||
{
|
||||
@@ -219,7 +219,7 @@ const SERVICE_ROLES: ServiceRole[] = [
|
||||
title: 'Credential seam',
|
||||
mode: 'seam',
|
||||
implementations: ['credentials-local'],
|
||||
consumers: ['llm-deepseek', 'llm-pi-ai', 'apiproxy'],
|
||||
consumers: ['llm-deepseek', 'llm-pi-ai', 'host-apiproxy'],
|
||||
note: 'Configuration carries references to secrets; providers own the values. Consumers resolve per operation, so a rotated credential reaches the very next request; the web gateway exposes value-free views and write-only storage.',
|
||||
},
|
||||
{
|
||||
@@ -269,7 +269,7 @@ const SERVICE_ROLES: ServiceRole[] = [
|
||||
pkg: 'workspace',
|
||||
title: 'Workspace entity registry',
|
||||
mode: 'core',
|
||||
consumers: ['apiproxy'],
|
||||
consumers: ['api-workspace-controller', 'api-session-controller'],
|
||||
note: 'Owns WorkspaceId-branded records over the domain facility; stable sessionIds accounts drive Host RPC and GUI projections.',
|
||||
},
|
||||
{
|
||||
@@ -379,7 +379,7 @@ const SERVICE_ROLES: ServiceRole[] = [
|
||||
pkg: 'agent',
|
||||
title: 'Agent service',
|
||||
mode: 'core',
|
||||
consumers: ['agent-loop', 'acp', 'subagent-inprocess'],
|
||||
consumers: ['agent-loop', 'acp', 'subagent-in-process-driver'],
|
||||
note: 'Owns live Agent handles, the create/resume factory seam, and process-local initiator propagation.',
|
||||
},
|
||||
{
|
||||
@@ -468,11 +468,11 @@ const SERVICE_ROLES: ServiceRole[] = [
|
||||
},
|
||||
{
|
||||
key: 'approval',
|
||||
pkg: 'approval',
|
||||
pkg: 'user-approval',
|
||||
title: 'Approval seam',
|
||||
mode: 'seam',
|
||||
implementations: ['acp'],
|
||||
consumers: ['tools', 'tool-bash'],
|
||||
implementations: [],
|
||||
consumers: ['tools', 'tool-bash', 'acp'],
|
||||
note: 'One-shot permission decisions dispatched over the `approval/request` waterfall; answerers are listeners (the ACP bridge for its own agents), absence fails closed to `unavailable`.',
|
||||
},
|
||||
{
|
||||
@@ -488,7 +488,7 @@ const SERVICE_ROLES: ServiceRole[] = [
|
||||
pkg: 'code-runtime',
|
||||
title: 'Code-execution seam',
|
||||
mode: 'seam',
|
||||
implementations: ['code-runtime-worker'],
|
||||
implementations: ['code-runtime-worker-thread'],
|
||||
consumers: ['tools'],
|
||||
note: 'Runs one model-written program against host-provided async bindings; backends differ by substrate and language (the tool registry consumes it for Code Mode).',
|
||||
},
|
||||
@@ -522,10 +522,10 @@ const SERVICE_ROLES: ServiceRole[] = [
|
||||
},
|
||||
{
|
||||
key: 'agentTeams',
|
||||
pkg: 'agent-team',
|
||||
pkg: 'experimental-agent-team',
|
||||
title: 'Agent Teams coordination domain',
|
||||
mode: 'core',
|
||||
consumers: ['tool-agent-team'],
|
||||
consumers: ['experimental-tool-agent-team'],
|
||||
note: 'Owns the implicit-root roster, durable peer mailbox, shared task DAG, and continuable-child lifecycle; tool-agent-team contributes the scoped model policy and controls.',
|
||||
},
|
||||
{
|
||||
@@ -557,27 +557,27 @@ const SERVICE_ROLES: ServiceRole[] = [
|
||||
},
|
||||
{
|
||||
key: 'directoryPicker',
|
||||
pkg: 'directory-picker',
|
||||
pkg: 'host-directory-picker',
|
||||
title: 'Workspace-directory picking seam',
|
||||
mode: 'seam',
|
||||
implementations: ['directory-picker-native', 'directory-picker-browse'],
|
||||
consumers: ['apiproxy'],
|
||||
implementations: ['host-directory-picker-native', 'host-directory-picker-browse'],
|
||||
consumers: ['host-apiproxy'],
|
||||
note: 'Discriminated interaction capability: the native backend opens one OS chooser on the host display, the browse backend serves listing/creation primitives for the in-app browser; dual-face backends fill ui-workspace directory-flow slots from their browser halves (no wire advertisement).',
|
||||
},
|
||||
{
|
||||
key: 'webServer',
|
||||
pkg: 'webserver',
|
||||
pkg: 'host-webserver',
|
||||
title: 'HTTP route registration',
|
||||
mode: 'core',
|
||||
consumers: ['connection', 'modules', 'hmr'],
|
||||
consumers: ['client-connection', 'client-modules', 'client-hmr'],
|
||||
note: 'Plain node:http carrier: named-route registry, index transform taps, and the static dist fallback; web-transport plugins register their own routes.',
|
||||
},
|
||||
{
|
||||
key: 'clientModules',
|
||||
pkg: 'modules',
|
||||
pkg: 'client-modules',
|
||||
title: 'Client plugin graph host',
|
||||
mode: 'core',
|
||||
consumers: ['hmr'],
|
||||
consumers: ['client-hmr'],
|
||||
note: 'Composes the __DSH_BOOT__ entry graph from an incremental dsh.client scan, serves plugin bundles, and notifies rebuilt/graph-changed subscribers.',
|
||||
},
|
||||
{
|
||||
@@ -602,16 +602,16 @@ const SERVICE_ROLES: ServiceRole[] = [
|
||||
pkg: 'lsp',
|
||||
title: 'Language-server navigation seam',
|
||||
mode: 'seam',
|
||||
implementations: ['lsp-local'],
|
||||
implementations: ['lsp-stdio'],
|
||||
consumers: ['tool-lsp'],
|
||||
note: 'Provider registration and selection plus normalized query execution over exactly four operations; the seam offers no protocol escape hatch, so a backend translates into the normalized request and result.',
|
||||
},
|
||||
{
|
||||
key: 'apiProxy',
|
||||
pkg: 'apiproxy',
|
||||
pkg: 'host-apiproxy',
|
||||
title: 'Host API dispatch',
|
||||
mode: 'core',
|
||||
consumers: ['connection'],
|
||||
consumers: ['client-connection'],
|
||||
note: 'The transport-agnostic host gateway face: it dispatches browser API calls, and each open host stream subscribes to the events it forwards rather than being pushed to through a broadcast verb.',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -368,7 +368,7 @@ export function render(events: AnnotatedLogEventEntry[], envelopeTypes: EventEnv
|
||||
'',
|
||||
'This file is GENERATED from source (`scripts/gen-persistence-catalog.ts`) and verified fresh by `pnpm run verify-persistence-catalog` (part of `doc-sync`) — do not edit it by hand. Declaration blocks retain the source declaration and nested property JSDoc, removing only the indentation imposed by a containing interface/module, and use a `ts persistence-catalog` fence (skipped by doc-typecheck because declarations reference types from their owning modules). Type names in a payload link to the page that documents them. See [the persistence-log-catalog Agent Note](../.agents/notes/archived/process/2026-07-04-persistence-log-catalog.md).',
|
||||
'',
|
||||
'The envelope declarations below compose each event\'s `type`, monotonic `seq`, epoch-ms `time`, `data`, the optional `ignorable` unknown-type skip marker, and the conditional `surfaceOp`/`sourceEventSeqs` fields. **surface** marks a `SurfaceEventType` member: it produces an LLM message and declares how it joins the surface list. **log-only** marks everything else: a durable, replayable record with no derived-history contribution. Every payload is JSON-serializable (enforced at `Session.append`), and the whole format is pinned at `SESSION_FORMAT_VERSION = 0` — pre-release, no compatibility implied ([the version stance](subsystems/persistence.md)). Scope: the packages in this repo; a downstream plugin can merge further event types, which are outside this catalog by construction.',
|
||||
'The envelope declarations below compose each event\'s `type`, monotonic `seq`, epoch-ms `time`, `data`, and the conditional `surfaceOp`/`sourceEventSeqs` fields. **surface** marks a `SurfaceEventType` member: it produces an LLM message and declares how it joins the surface list. **log-only** marks everything else: a durable, replayable record with no derived-history contribution. Every payload is JSON-serializable (enforced at `Session.append`), and the whole format is pinned at `SESSION_FORMAT_VERSION = 0` — pre-release, no compatibility implied ([the version stance](subsystems/persistence.md)). Scope: the packages in this repo; a downstream plugin can merge further event types, which are outside this catalog by construction.',
|
||||
'',
|
||||
'## Event envelope',
|
||||
'',
|
||||
@@ -394,7 +394,7 @@ export function render(events: AnnotatedLogEventEntry[], envelopeTypes: EventEnv
|
||||
/**
|
||||
* Render the runtime known-vocabulary module: every event type the packages in
|
||||
* this repo can write, as a generated `ReadonlySet` the read path checks
|
||||
* unknown-type refusal against (`SessionEvent.ignorable` contract).
|
||||
* before reconstructing a stored session.
|
||||
*/
|
||||
export function renderKnownEventTypes(events: AnnotatedLogEventEntry[]): string {
|
||||
const names = [...new Set(events.map(e => e.name))].sort()
|
||||
@@ -409,10 +409,9 @@ export function renderKnownEventTypes(events: AnnotatedLogEventEntry[]): string
|
||||
'/**',
|
||||
' * Every `SessionEventMap` member declared in this repository — the event',
|
||||
' * vocabulary this build understands. The persistence read path refuses to',
|
||||
' * interpret a log containing a type outside this set unless the event',
|
||||
' * carries the envelope\'s `ignorable` marker (see `SessionEvent.ignorable`',
|
||||
' * in `./types.ts`): such a log was likely written by a newer harness, and',
|
||||
' * silently skipping a required event would reconstruct a wrong session.',
|
||||
' * interpret a log containing a type outside this set: such a log was likely',
|
||||
' * written by a newer harness, and silently skipping the event could',
|
||||
' * reconstruct a wrong session.',
|
||||
' * Downstream (out-of-repo) plugin events are outside this list by',
|
||||
' * construction; a registration surface for them is deferred until such a',
|
||||
' * consumer exists.',
|
||||
|
||||
@@ -71,6 +71,7 @@ describe('gate graph validation', () => {
|
||||
'check-all',
|
||||
'hygiene',
|
||||
'doc-sync',
|
||||
'doc-quick',
|
||||
] as const)('constructs and executes preflight for a valid non-empty %s graph', async (mode) => {
|
||||
const subject = withPnpmEntrypoint(() => gatesForMode(mode))
|
||||
const execute = vi.fn(async (item: Gate) => resultFor(item))
|
||||
@@ -90,6 +91,13 @@ describe('gate graph validation', () => {
|
||||
expect(ids).toContain('subsystem-pages')
|
||||
})
|
||||
|
||||
it('derives the quick documentation aggregate from marked doc-sync leaves', () => {
|
||||
const full = withPnpmEntrypoint(() => gatesForMode('doc-sync'))
|
||||
const quick = withPnpmEntrypoint(() => gatesForMode('doc-quick'))
|
||||
|
||||
expect(quick).toEqual(full.filter(gate => gate.quick === true))
|
||||
})
|
||||
|
||||
it('keeps the hygiene aggregate aligned with the package script checks', () => {
|
||||
const ids = withPnpmEntrypoint(() => gatesForMode('hygiene').map(subject => subject.id))
|
||||
|
||||
@@ -167,9 +175,13 @@ describe('gate graph validation', () => {
|
||||
const byId = new Map(complete.map(subject => [subject.id, subject]))
|
||||
|
||||
expect(byId.get('coverage')?.allowFailure).not.toBe(true)
|
||||
expect(byId.get('coverage')?.needs).toContain('build')
|
||||
expect(byId.get('coverage-exempt-heavy')?.allowFailure).not.toBe(true)
|
||||
expect(byId.get('coverage')?.needs).toContain('build')
|
||||
expect(byId.get('coverage-exempt-heavy')?.needs).toContain('build')
|
||||
expect(byId.get('coverage-exempt-heavy')?.args).toContain(
|
||||
'packages/experimental/webworker-packer/tests/image-loadable.spec.ts',
|
||||
)
|
||||
expect(observational).not.toHaveLength(0)
|
||||
for (const gate of observational) {
|
||||
const completeGate = byId.get(gate.id)
|
||||
@@ -218,6 +230,7 @@ describe('gate graph validation', () => {
|
||||
expect(coverage).toMatchObject({
|
||||
displayCommand: 'DSH_COVERAGE_PARTITIONS=3 pnpm run test:coverage:partitioned',
|
||||
args: ['/private/pnpm.cjs', 'run', 'test:coverage:partitioned'],
|
||||
env: { DSH_COVERAGE_EXEMPT_HEAVY: '1' },
|
||||
streamOutput: true,
|
||||
})
|
||||
})
|
||||
|
||||
+38
-16
@@ -36,6 +36,7 @@ export type Mode =
|
||||
| 'check-all'
|
||||
| 'hygiene'
|
||||
| 'doc-sync'
|
||||
| 'doc-quick'
|
||||
|
||||
type GateResultStatus = 'passed' | 'failed' | 'skipped'
|
||||
type GateState = 'pending' | 'running' | GateResultStatus
|
||||
@@ -51,6 +52,8 @@ export interface Gate {
|
||||
/** Gate ids that must settle, regardless of outcome, before this gate starts. */
|
||||
after?: string[]
|
||||
env?: Record<string, string | undefined>
|
||||
/** Include this leaf in the build-free documentation aggregate. */
|
||||
quick?: boolean
|
||||
/** Keep a failure visible without failing the aggregate. */
|
||||
allowFailure?: boolean
|
||||
/** Write child output as it arrives instead of buffering it until completion. */
|
||||
@@ -127,10 +130,11 @@ function parseMode(raw: string | undefined): Mode {
|
||||
case 'check-all':
|
||||
case 'hygiene':
|
||||
case 'doc-sync':
|
||||
case 'doc-quick':
|
||||
return raw
|
||||
default:
|
||||
throw new Error(
|
||||
`run-gates: expected mode ci-primary | ci-linux-primary | ci-static | ci-lint-contracts-ready | ci-coverage | ci-snapshot | ci-artifacts | ci-consumers | ci-windows-blocking | ci-windows-complete | ci-windows-observational | node-compat | check-all | hygiene | doc-sync, got ${JSON.stringify(raw)}.`,
|
||||
`run-gates: expected mode ci-primary | ci-linux-primary | ci-static | ci-lint-contracts-ready | ci-coverage | ci-snapshot | ci-artifacts | ci-consumers | ci-windows-blocking | ci-windows-complete | ci-windows-observational | node-compat | check-all | hygiene | doc-sync | doc-quick, got ${JSON.stringify(raw)}.`,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -150,7 +154,10 @@ export function defaultConcurrency(
|
||||
if (selectedMode === 'ci-consumers') return { workers: total, source: 'ci-consumers gate count' }
|
||||
// Local modes cap workers: several doc gates each build a full ts.Program,
|
||||
// so an uncapped default on a large host trades wall clock for memory blowups.
|
||||
const localCap = selectedMode === 'check-all' || selectedMode === 'hygiene' || selectedMode === 'doc-sync'
|
||||
const localCap = selectedMode === 'check-all'
|
||||
|| selectedMode === 'hygiene'
|
||||
|| selectedMode === 'doc-sync'
|
||||
|| selectedMode === 'doc-quick'
|
||||
const modeLimit = localCap ? Math.min(4, available) : available
|
||||
return {
|
||||
workers: Math.min(total, modeLimit),
|
||||
@@ -261,6 +268,8 @@ export function gatesForMode(selected: Mode): Gate[] {
|
||||
]
|
||||
case 'doc-sync':
|
||||
return docSyncLeafGates()
|
||||
case 'doc-quick':
|
||||
return docQuickLeafGates()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -683,38 +692,51 @@ function docSyncLeafGates(options: {
|
||||
: [pnpmScript('doc-typecheck', options.docTypecheckScript ?? 'doc-typecheck', docTypecheckOptions)],
|
||||
pnpmScript('docs-site-build', options.docsBuildScript ?? 'docs:build', { label: 'documentation build' }),
|
||||
pnpmScript('doc-graphs', 'verify-doc-graphs', { label: 'doc graphs' }),
|
||||
pnpmScript('markdown-links', 'verify-md-links', { label: 'markdown links' }),
|
||||
pnpmScript('type-equivalence', 'verify-type-equiv', { label: 'type equivalence' }),
|
||||
pnpmScript('markdown-links', 'verify-md-links', { label: 'markdown links', quick: true }),
|
||||
pnpmScript('type-equivalence', 'verify-type-equiv', { label: 'type equivalence', quick: true }),
|
||||
pnpmScript('cordis-catalog', 'verify-cordis-catalog', { label: 'cordis catalog' }),
|
||||
pnpmScript('cordis-inspect-catalog', 'verify-cordis-inspect-catalog', { label: 'Cordis inspect catalog' }),
|
||||
pnpmScript('mermaid', 'verify-mermaid'),
|
||||
pnpmScript('scoped-events', 'verify-scoped-events', { label: 'scoped events' }),
|
||||
pnpmScript('translation-pairing', 'verify-translation-pairing', { label: 'translation pairing' }),
|
||||
pnpmScript('markdown-wrap', 'verify-md-wrap', { label: 'markdown wrap' }),
|
||||
pnpmScript('translation-pairing', 'verify-translation-pairing', { label: 'translation pairing', quick: true }),
|
||||
pnpmScript('markdown-wrap', 'verify-md-wrap', { label: 'markdown wrap', quick: true }),
|
||||
pnpmScript('client-catalog', 'verify-client-catalog', { label: 'client catalog' }),
|
||||
pnpmScript('export-jsdoc', 'verify-export-jsdoc', { label: 'export jsdoc' }),
|
||||
pnpmScript('tool-catalog', 'verify-tool-catalog', { label: 'tool catalog' }),
|
||||
pnpmScript('config-catalog', 'verify-config-catalog', { label: 'config catalog' }),
|
||||
pnpmScript('persistence-catalog', 'verify-persistence-catalog', { label: 'persistence catalog' }),
|
||||
pnpmScript('public-repository-links', 'verify-public-repository-links', { label: 'public repository links' }),
|
||||
pnpmScript('doc-refs', 'verify-doc-refs', { label: 'doc refs' }),
|
||||
pnpmScript('public-repository-links', 'verify-public-repository-links', { label: 'public repository links', quick: true }),
|
||||
pnpmScript('doc-refs', 'verify-doc-refs', { label: 'doc refs', quick: true }),
|
||||
pnpmScript('subsystem-pages', 'verify-subsystem-pages', { label: 'subsystem pages' }),
|
||||
pnpmScript('package-paths', 'verify-package-paths', { label: 'package paths' }),
|
||||
pnpmScript('config-source-ownership', 'verify-config-source-ownership', { label: 'config source ownership' }),
|
||||
pnpmScript('package-readme-model-experience', 'verify-package-readme-model-experience', { label: 'package README model experience' }),
|
||||
pnpmScript('agent-note-classification', 'verify-agent-note-classification', { label: 'agent note classification' }),
|
||||
pnpmScript('agent-note-format', 'verify-agent-note-format', { label: 'agent note format' }),
|
||||
pnpmScript('archived-agent-notes', 'verify-archived-agent-notes', { label: 'archived agent notes' }),
|
||||
pnpmScript('skill-invocation-metadata', 'verify-skill-invocation-metadata', { label: 'skill invocation metadata' }),
|
||||
pnpmScript('translation-prompt', 'verify-translation-prompt', { label: 'translation prompt' }),
|
||||
pnpmScript('doc-budgets', 'verify-doc-budgets', { label: 'doc budgets' }),
|
||||
pnpmScript('package-readme-model-experience', 'verify-package-readme-model-experience', { label: 'package README model experience', quick: true }),
|
||||
pnpmScript('agent-note-classification', 'verify-agent-note-classification', { label: 'agent note classification', quick: true }),
|
||||
pnpmScript('agent-note-format', 'verify-agent-note-format', { label: 'agent note format', quick: true }),
|
||||
pnpmScript('archived-agent-notes', 'verify-archived-agent-notes', { label: 'archived agent notes', quick: true }),
|
||||
pnpmScript('skill-invocation-metadata', 'verify-skill-invocation-metadata', { label: 'skill invocation metadata', quick: true }),
|
||||
pnpmScript('translation-prompt', 'verify-translation-prompt', { label: 'translation prompt', quick: true }),
|
||||
pnpmScript('doc-budgets', 'verify-doc-budgets', { label: 'doc budgets', quick: true }),
|
||||
pnpmExec('doc-standard-tests', ['vitest', 'run', 'scripts/doc-standard.spec.ts'], {
|
||||
label: 'documentation standard tests',
|
||||
quick: true,
|
||||
}),
|
||||
pnpmExec('docs-site-projection', ['vitest', 'run', 'scripts/project-doc-site.spec.ts', 'scripts/verify-doc-site-fragments.spec.ts'], {
|
||||
label: 'documentation site checks',
|
||||
}),
|
||||
pnpmScript('package-readme-limitations', 'verify-package-readme-limitations', { label: 'package README limitations' }),
|
||||
pnpmScript('package-readme-limitations', 'verify-package-readme-limitations', { label: 'package README limitations', quick: true }),
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* The quick comprehensive documentation-standard aggregate for `test:docs`.
|
||||
* It covers the prose, pairing, README, budget, and Agent Note gates
|
||||
* without builds, generator regeneration, or the VitePress site build.
|
||||
*/
|
||||
function docQuickLeafGates(): Gate[] {
|
||||
return docSyncLeafGates({ includeDocTypecheck: false }).filter(gate => gate.quick === true)
|
||||
}
|
||||
|
||||
function builtBinSmokeGate(needs: string[] = ['build']): Gate {
|
||||
return pnpmExec('built-bin-smoke', [
|
||||
'vitest',
|
||||
|
||||
@@ -40,7 +40,7 @@ function signature(markdown: string) {
|
||||
'counterpart.zh.md',
|
||||
{
|
||||
repoRoot: process.cwd(), sourcePath: 'counterpart.md',
|
||||
isTranslationPairSource: fixturePairSource, markdown,
|
||||
isTranslationPairSource: fixturePairSource, repositoryFileExists: () => true, markdown,
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -250,6 +250,30 @@ describe('translation pairing switchers', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('translation pairing link language parity', () => {
|
||||
it('compares a .zh.md target and its .md sibling as the same document', () => {
|
||||
const en = 'See [docs](persistence.md) and [notes](note.md#anchor).'
|
||||
const zh = '参见[文档](persistence.zh.md)与[笔记](note.zh.md#anchor)。'
|
||||
expect(
|
||||
translationStructureDiff(
|
||||
signature(en),
|
||||
signature(zh),
|
||||
),
|
||||
).toEqual([])
|
||||
})
|
||||
|
||||
it('still rejects a genuinely different target', () => {
|
||||
const en = 'See [docs](persistence.md).'
|
||||
const zh = '参见[文档](other.md)。'
|
||||
expect(
|
||||
translationStructureDiff(
|
||||
signature(en),
|
||||
signature(zh),
|
||||
),
|
||||
).not.toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('translation pairing records', () => {
|
||||
const paths = translationPairPaths('docs/foo.md')
|
||||
const record = {
|
||||
|
||||
@@ -16,16 +16,10 @@ const root = resolve(import.meta.dirname, '..')
|
||||
*/
|
||||
export const GROUPS_WITHOUT_SUBSYSTEM_PAGE: Readonly<Record<string, string>> = {
|
||||
acp: 'Protocol transport entry point; the server package README owns its interoperability contract.',
|
||||
api: 'Remote transport and BFF assembly; Typert and the package READMEs own the underlying contracts.',
|
||||
boot: 'Shared application-bin boot library rather than a runtime subsystem.',
|
||||
bundle: 'Composition patch carriers whose mounted packages own all runtime contracts.',
|
||||
e2b: 'Provider implementations of the filesystem and subprocess subsystems, not a new capability contract.',
|
||||
examples: 'Non-product demonstration compositions whose mounted packages own all runtime contracts.',
|
||||
experimental: 'Empty staging group; promoted packages move to their product-role group before release.',
|
||||
feedback: 'One command producer and inline log-event payload; its package README and persistence catalog own the complete contract.',
|
||||
hooks: 'External hook-protocol bridges over existing interception points, not a new Harness service.',
|
||||
identity: 'Shared anonymous correlation values rather than authenticated account or authorization behavior.',
|
||||
mcp: 'Integration adapter that contributes external tools through the existing tool registry.',
|
||||
sdk: 'Out-of-process protocol and client packages whose package READMEs own the SDK contracts.',
|
||||
util: 'Low-level primitives whose business semantics remain with their consuming subsystems.',
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user