From 1a39953f69eccde7ff35180eabb70be9aba5060e Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:29:39 +0800 Subject: [PATCH] docs(i18n): address RFC translation review --- ...6-06-11-content-block-vocabulary.i18n.yaml | 4 +- .../2026-06-11-content-block-vocabulary.md | 4 +- .../2026-06-11-content-block-vocabulary.zh.md | 2 +- .../2026-06-11-custom-schema-dsl.i18n.yaml | 4 +- .../2026-06-11-custom-schema-dsl.md | 4 +- .../2026-06-11-custom-schema-dsl.zh.md | 4 +- ...ev-invariants-over-deep-readonly.i18n.yaml | 4 +- ...06-11-dev-invariants-over-deep-readonly.md | 4 +- ...11-dev-invariants-over-deep-readonly.zh.md | 2 +- ...026-06-11-event-sourced-sessions.i18n.yaml | 4 +- .../2026-06-11-event-sourced-sessions.md | 4 +- .../2026-06-11-event-sourced-sessions.zh.md | 8 +-- ...06-11-microkernel-event-taxonomy.i18n.yaml | 4 +- .../2026-06-11-microkernel-event-taxonomy.md | 4 +- ...026-06-11-microkernel-event-taxonomy.zh.md | 2 +- ...026-06-11-runtime-arg-validation.i18n.yaml | 4 +- .../2026-06-11-runtime-arg-validation.md | 4 +- .../2026-06-11-runtime-arg-validation.zh.md | 2 +- ...-06-11-structured-error-taxonomy.i18n.yaml | 4 +- .../2026-06-11-structured-error-taxonomy.md | 4 +- ...2026-06-11-structured-error-taxonomy.zh.md | 2 +- ...-tool-schemas-in-prompt-assembly.i18n.yaml | 4 +- ...6-06-11-tool-schemas-in-prompt-assembly.md | 4 +- ...6-11-tool-schemas-in-prompt-assembly.zh.md | 2 +- .../2026-06-13-capability-seams.i18n.yaml | 4 +- .../2026-06-13-capability-seams.md | 4 +- .../2026-06-13-capability-seams.zh.md | 8 +-- .../2026-06-13-twin-llm-adapters.i18n.yaml | 4 +- .../2026-06-13-twin-llm-adapters.md | 4 +- .../2026-06-13-twin-llm-adapters.zh.md | 2 +- .../2026-06-14-session-persistence.i18n.yaml | 4 +- .../2026-06-14-session-persistence.md | 4 +- .../2026-06-14-session-persistence.zh.md | 4 +- ...6-06-15-turn-enclosure-invariant.i18n.yaml | 4 +- .../2026-06-15-turn-enclosure-invariant.md | 4 +- .../2026-06-15-turn-enclosure-invariant.zh.md | 4 +- ...06-17-filesystem-capability-seam.i18n.yaml | 4 +- .../2026-06-17-filesystem-capability-seam.md | 4 +- ...026-06-17-filesystem-capability-seam.zh.md | 18 ++--- ...nt-lifecycle-and-ownership-seams.i18n.yaml | 4 +- ...-18-agent-lifecycle-and-ownership-seams.md | 4 +- ...-agent-lifecycle-and-ownership-seams.zh.md | 6 +- .../2026-06-18-session-surface.i18n.yaml | 4 +- .../2026-06-18-session-surface.md | 4 +- .../2026-06-18-session-surface.zh.md | 6 +- ...ed-persistence-write-coordinator.i18n.yaml | 4 +- ...18-shared-persistence-write-coordinator.md | 4 +- ...shared-persistence-write-coordinator.zh.md | 18 ++--- .../2026-06-20-branded-ids.i18n.yaml | 4 +- .../architecture/2026-06-20-branded-ids.md | 4 +- .../architecture/2026-06-20-branded-ids.zh.md | 14 ++-- ...-20-extract-example-app-packages.i18n.yaml | 4 +- ...2026-06-20-extract-example-app-packages.md | 4 +- ...6-06-20-extract-example-app-packages.zh.md | 6 +- .../2026-06-20-package-hierarchy.i18n.yaml | 4 +- .../2026-06-20-package-hierarchy.md | 4 +- .../2026-06-20-package-hierarchy.zh.md | 6 +- ...andatory-app-attribution-headers.i18n.yaml | 4 +- ...06-21-mandatory-app-attribution-headers.md | 4 +- ...21-mandatory-app-attribution-headers.zh.md | 10 +-- .../2026-06-24-web-capability-seam.i18n.yaml | 4 +- .../2026-06-24-web-capability-seam.md | 4 +- .../2026-06-24-web-capability-seam.zh.md | 2 +- ...06-26-file-context-as-event-gate.i18n.yaml | 4 +- .../2026-06-26-file-context-as-event-gate.md | 4 +- ...026-06-26-file-context-as-event-gate.zh.md | 6 +- ...stdin-env-trusted-plugin-surface.i18n.yaml | 4 +- ...0-bash-stdin-env-trusted-plugin-surface.md | 4 +- ...ash-stdin-env-trusted-plugin-surface.zh.md | 2 +- ...026-06-30-event-domain-semantics.i18n.yaml | 4 +- .../2026-06-30-event-domain-semantics.md | 4 +- .../2026-06-30-event-domain-semantics.zh.md | 8 +-- .../2026-07-02-fs-per-session-cwd.i18n.yaml | 4 +- .../2026-07-02-fs-per-session-cwd.md | 4 +- .../2026-07-02-fs-per-session-cwd.zh.md | 8 +-- ...2-result-time-applied-hunk-diffs.i18n.yaml | 4 +- ...26-07-02-result-time-applied-hunk-diffs.md | 4 +- ...07-02-result-time-applied-hunk-diffs.zh.md | 10 +-- ...6-07-02-tool-render-intent-union.i18n.yaml | 4 +- .../2026-07-02-tool-render-intent-union.md | 4 +- .../2026-07-02-tool-render-intent-union.zh.md | 2 +- ...ilesystem-directory-listing-seam.i18n.yaml | 4 +- ...07-03-filesystem-directory-listing-seam.md | 4 +- ...03-filesystem-directory-listing-seam.zh.md | 6 +- ...bles-and-tool-guidance-ownership.i18n.yaml | 4 +- ...t-variables-and-tool-guidance-ownership.md | 4 +- ...ariables-and-tool-guidance-ownership.zh.md | 12 ++-- ...6-07-05-reconstructable-requests.i18n.yaml | 4 +- .../2026-07-05-reconstructable-requests.md | 4 +- .../2026-07-05-reconstructable-requests.zh.md | 4 +- ...bagent-provider-lifecycle-events.i18n.yaml | 4 +- ...7-05-subagent-provider-lifecycle-events.md | 4 +- ...5-subagent-provider-lifecycle-events.zh.md | 16 ++--- ...6-07-06-timeout-deadline-library.i18n.yaml | 4 +- .../2026-07-06-timeout-deadline-library.md | 4 +- .../2026-07-06-timeout-deadline-library.zh.md | 2 +- ...6-07-07-tool-call-timeout-policy.i18n.yaml | 4 +- .../2026-07-07-tool-call-timeout-policy.md | 4 +- .../2026-07-07-tool-call-timeout-policy.zh.md | 10 +-- .../2026-07-08-agent-scope-contexts.i18n.yaml | 4 +- .../2026-07-08-agent-scope-contexts.md | 4 +- .../2026-07-08-agent-scope-contexts.zh.md | 2 +- ...07-12-agent-scope-runtime-design.i18n.yaml | 4 +- .../2026-07-12-agent-scope-runtime-design.md | 4 +- ...026-07-12-agent-scope-runtime-design.zh.md | 6 +- ...-06-14-acp-agent-client-protocol.i18n.yaml | 4 +- .../2026-06-14-acp-agent-client-protocol.md | 4 +- ...2026-06-14-acp-agent-client-protocol.zh.md | 6 +- .../2026-06-14-acp-multi-session.i18n.yaml | 4 +- .../feature/2026-06-14-acp-multi-session.md | 4 +- .../2026-06-14-acp-multi-session.zh.md | 6 +- .../feature/2026-06-15-code-mode.i18n.yaml | 4 +- .../feature/2026-06-15-code-mode.md | 4 +- .../feature/2026-06-15-code-mode.zh.md | 8 +-- ...26-06-17-filesystem-tool-schemas.i18n.yaml | 4 +- .../2026-06-17-filesystem-tool-schemas.md | 4 +- .../2026-06-17-filesystem-tool-schemas.zh.md | 16 ++--- ...-acp-terminal-and-tool-rendering.i18n.yaml | 4 +- ...6-06-18-acp-terminal-and-tool-rendering.md | 4 +- ...6-18-acp-terminal-and-tool-rendering.zh.md | 8 +-- ...06-18-compaction-capability-seam.i18n.yaml | 4 +- .../2026-06-18-compaction-capability-seam.md | 4 +- ...026-06-18-compaction-capability-seam.zh.md | 4 +- ...6-06-21-subagent-capability-seam.i18n.yaml | 4 +- .../2026-06-21-subagent-capability-seam.md | 4 +- .../2026-06-21-subagent-capability-seam.zh.md | 8 +-- .../2026-06-22-acp-subagent-backend.i18n.yaml | 4 +- .../2026-06-22-acp-subagent-backend.md | 4 +- .../2026-06-22-acp-subagent-backend.zh.md | 12 ++-- .../2026-06-25-ask-user-question.i18n.yaml | 4 +- .../feature/2026-06-25-ask-user-question.md | 4 +- .../2026-06-25-ask-user-question.zh.md | 6 +- .../2026-06-29-todo-write-tool.i18n.yaml | 4 +- .../feature/2026-06-29-todo-write-tool.md | 4 +- .../feature/2026-06-29-todo-write-tool.zh.md | 8 +-- .../feature/2026-06-30-hook-bridges.i18n.yaml | 4 +- .../feature/2026-06-30-hook-bridges.md | 4 +- .../feature/2026-06-30-hook-bridges.zh.md | 4 +- .../2026-06-30-hook-protocol-lib.i18n.yaml | 4 +- .../feature/2026-06-30-hook-protocol-lib.md | 4 +- .../2026-06-30-hook-protocol-lib.zh.md | 8 +-- .../2026-06-30-interception-seams.i18n.yaml | 4 +- .../feature/2026-06-30-interception-seams.md | 4 +- .../2026-06-30-interception-seams.zh.md | 6 +- ...026-06-30-session-store-fork-api.i18n.yaml | 4 +- .../2026-06-30-session-store-fork-api.md | 4 +- .../2026-06-30-session-store-fork-api.zh.md | 6 +- ...26-06-30-subagent-observe-enrich.i18n.yaml | 4 +- .../2026-06-30-subagent-observe-enrich.md | 4 +- .../2026-06-30-subagent-observe-enrich.zh.md | 2 +- .../2026-07-05-dynamic-workflows.i18n.yaml | 4 +- .../feature/2026-07-05-dynamic-workflows.md | 4 +- .../2026-07-05-dynamic-workflows.zh.md | 12 ++-- .../feature/2026-07-05-skill-system.i18n.yaml | 4 +- .../feature/2026-07-05-skill-system.md | 4 +- .../feature/2026-07-05-skill-system.zh.md | 6 +- .../2026-07-06-approval-seam.i18n.yaml | 4 +- .../feature/2026-07-06-approval-seam.md | 4 +- .../feature/2026-07-06-approval-seam.zh.md | 6 +- .../2026-07-06-explicit-tool-order.i18n.yaml | 4 +- .../feature/2026-07-06-explicit-tool-order.md | 4 +- .../2026-07-06-explicit-tool-order.zh.md | 6 +- .../feature/2026-07-06-sandbox.i18n.yaml | 4 +- .../implemented/feature/2026-07-06-sandbox.md | 4 +- .../feature/2026-07-06-sandbox.zh.md | 72 +++++++++---------- .../2026-07-07-mcp-client-plugin.i18n.yaml | 4 +- .../feature/2026-07-07-mcp-client-plugin.md | 4 +- .../2026-07-07-mcp-client-plugin.zh.md | 4 +- .../2026-07-07-session-prefix.i18n.yaml | 4 +- .../feature/2026-07-07-session-prefix.md | 4 +- .../feature/2026-07-07-session-prefix.zh.md | 10 +-- .../2026-07-08-repeat-tool-guard.i18n.yaml | 4 +- .../feature/2026-07-08-repeat-tool-guard.md | 4 +- .../2026-07-08-repeat-tool-guard.zh.md | 2 +- ...-self-referential-cordis-toolset.i18n.yaml | 4 +- ...6-07-08-self-referential-cordis-toolset.md | 4 +- ...7-08-self-referential-cordis-toolset.zh.md | 6 +- ...2026-07-10-session-query-service.i18n.yaml | 4 +- .../2026-07-10-session-query-service.md | 4 +- .../2026-07-10-session-query-service.zh.md | 6 +- ...nt-persona-tool-filter-and-depth.i18n.yaml | 4 +- ...-subagent-persona-tool-filter-and-depth.md | 4 +- ...bagent-persona-tool-filter-and-depth.zh.md | 6 +- .../2026-06-11-doc-sync-enforcement.i18n.yaml | 4 +- .../2026-06-11-doc-sync-enforcement.md | 4 +- .../2026-06-11-doc-sync-enforcement.zh.md | 8 +-- .../2026-06-11-quality-gates.i18n.yaml | 4 +- .../process/2026-06-11-quality-gates.md | 4 +- .../process/2026-06-11-quality-gates.zh.md | 8 +-- .../2026-06-11-tsdown-over-dumble.i18n.yaml | 4 +- .../process/2026-06-11-tsdown-over-dumble.md | 4 +- .../2026-06-11-tsdown-over-dumble.zh.md | 6 +- ...26-06-11-vendor-cordis-as-source.i18n.yaml | 4 +- .../2026-06-11-vendor-cordis-as-source.md | 4 +- .../2026-06-11-vendor-cordis-as-source.zh.md | 6 +- .../2026-06-16-pnpm-over-yarn.i18n.yaml | 4 +- .../process/2026-06-16-pnpm-over-yarn.md | 4 +- .../process/2026-06-16-pnpm-over-yarn.zh.md | 6 +- .../2026-06-17-ts-build-config.i18n.yaml | 4 +- .../process/2026-06-17-ts-build-config.md | 4 +- .../process/2026-06-17-ts-build-config.zh.md | 8 +-- ...6-06-18-markdown-cross-link-lint.i18n.yaml | 4 +- .../2026-06-18-markdown-cross-link-lint.md | 4 +- .../2026-06-18-markdown-cross-link-lint.zh.md | 8 +-- ...-20-core-data-structures-catalog.i18n.yaml | 4 +- ...2026-06-20-core-data-structures-catalog.md | 4 +- ...6-06-20-core-data-structures-catalog.zh.md | 6 +- ...6-06-20-generated-cordis-catalog.i18n.yaml | 4 +- .../2026-06-20-generated-cordis-catalog.md | 4 +- .../2026-06-20-generated-cordis-catalog.zh.md | 6 +- .../2026-06-20-rfc-classification.i18n.yaml | 4 +- .../process/2026-06-20-rfc-classification.md | 4 +- .../2026-06-20-rfc-classification.zh.md | 10 +-- .../2026-07-02-tool-schema-catalog.i18n.yaml | 4 +- .../process/2026-07-02-tool-schema-catalog.md | 4 +- .../2026-07-02-tool-schema-catalog.zh.md | 10 +-- ...-07-03-documentation-graph-atlas.i18n.yaml | 4 +- .../2026-07-03-documentation-graph-atlas.md | 4 +- ...2026-07-03-documentation-graph-atlas.zh.md | 6 +- ...4-cordis-jsdoc-completeness-gate.i18n.yaml | 4 +- ...26-07-04-cordis-jsdoc-completeness-gate.md | 4 +- ...07-04-cordis-jsdoc-completeness-gate.zh.md | 8 +-- ...2026-07-04-doc-tiers-and-budgets.i18n.yaml | 4 +- .../2026-07-04-doc-tiers-and-budgets.md | 4 +- .../2026-07-04-doc-tiers-and-budgets.zh.md | 6 +- ...-07-04-generate-rfc-index-tables.i18n.yaml | 4 +- .../2026-07-04-generate-rfc-index-tables.md | 4 +- ...2026-07-04-generate-rfc-index-tables.zh.md | 8 +-- ...26-07-04-persistence-log-catalog.i18n.yaml | 4 +- .../2026-07-04-persistence-log-catalog.md | 4 +- .../2026-07-04-persistence-log-catalog.zh.md | 2 +- .../2026-07-05-uniform-rfc-format.i18n.yaml | 4 +- .../process/2026-07-05-uniform-rfc-format.md | 4 +- .../2026-07-05-uniform-rfc-format.zh.md | 8 +-- ...-07-06-export-surface-jsdoc-gate.i18n.yaml | 4 +- .../2026-07-06-export-surface-jsdoc-gate.md | 4 +- ...2026-07-06-export-surface-jsdoc-gate.zh.md | 10 +-- ...6-07-06-generated-config-catalog.i18n.yaml | 4 +- .../2026-07-06-generated-config-catalog.md | 4 +- .../2026-07-06-generated-config-catalog.zh.md | 2 +- .../2026-07-06-node-engine-floor.i18n.yaml | 4 +- .../process/2026-07-06-node-engine-floor.md | 4 +- .../2026-07-06-node-engine-floor.zh.md | 6 +- ...6-07-06-parallel-github-ci-gates.i18n.yaml | 4 +- .../2026-07-06-parallel-github-ci-gates.md | 4 +- .../2026-07-06-parallel-github-ci-gates.zh.md | 6 +- ...26-07-06-parallel-pre-push-gates.i18n.yaml | 4 +- .../2026-07-06-parallel-pre-push-gates.md | 4 +- .../2026-07-06-parallel-pre-push-gates.zh.md | 6 +- ...10-readme-known-limitations-gate.i18n.yaml | 4 +- ...026-07-10-readme-known-limitations-gate.md | 4 +- ...-07-10-readme-known-limitations-gate.zh.md | 6 +- ...ackage-model-experience-contract.i18n.yaml | 4 +- ...07-12-package-model-experience-contract.md | 4 +- ...12-package-model-experience-contract.zh.md | 8 +-- ...-19-drop-mutable-session-summary.i18n.yaml | 4 +- ...2026-06-19-drop-mutable-session-summary.md | 4 +- ...6-06-19-drop-mutable-session-summary.zh.md | 8 +-- ...llapse-trace-only-session-events.i18n.yaml | 4 +- ...6-20-collapse-trace-only-session-events.md | 4 +- ...0-collapse-trace-only-session-events.zh.md | 2 +- ...onsumed-llm-adapter-change-event.i18n.yaml | 4 +- ...rop-unconsumed-llm-adapter-change-event.md | 4 +- ...-unconsumed-llm-adapter-change-event.zh.md | 2 +- ...nconsumed-llm-assembled-surfaces.i18n.yaml | 4 +- ...-drop-unconsumed-llm-assembled-surfaces.md | 4 +- ...op-unconsumed-llm-assembled-surfaces.zh.md | 2 +- ...26-06-20-prune-dead-seam-methods.i18n.yaml | 4 +- .../2026-06-20-prune-dead-seam-methods.md | 4 +- .../2026-06-20-prune-dead-seam-methods.zh.md | 6 +- ...-06-20-public-agent-stop-surface.i18n.yaml | 4 +- .../2026-06-20-public-agent-stop-surface.md | 4 +- ...2026-06-20-public-agent-stop-surface.zh.md | 2 +- ...ove-agent-boundary-mirror-events.i18n.yaml | 4 +- ...-20-remove-agent-boundary-mirror-events.md | 4 +- ...-remove-agent-boundary-mirror-events.zh.md | 6 +- .../2026-06-26-fsspec-style-fs-seam.i18n.yaml | 4 +- .../2026-06-26-fsspec-style-fs-seam.md | 4 +- .../2026-06-26-fsspec-style-fs-seam.zh.md | 20 +++--- ...07-02-remove-stream-chunk-mirror.i18n.yaml | 4 +- .../2026-07-02-remove-stream-chunk-mirror.md | 4 +- ...026-07-02-remove-stream-chunk-mirror.zh.md | 6 +- ...6-07-04-drop-image-content-block.i18n.yaml | 4 +- .../2026-07-04-drop-image-content-block.md | 4 +- .../2026-07-04-drop-image-content-block.zh.md | 8 +-- ...6-07-04-drop-inert-request-knobs.i18n.yaml | 4 +- .../2026-07-04-drop-inert-request-knobs.md | 4 +- .../2026-07-04-drop-inert-request-knobs.zh.md | 12 ++-- ...consumed-web-observation-surface.i18n.yaml | 4 +- ...drop-unconsumed-web-observation-surface.md | 4 +- ...p-unconsumed-web-observation-surface.zh.md | 4 +- .../2026-07-04-fold-stdio-ui-helper.i18n.yaml | 4 +- .../2026-07-04-fold-stdio-ui-helper.md | 4 +- .../2026-07-04-fold-stdio-ui-helper.zh.md | 6 +- ...producerless-vocabulary-variants.i18n.yaml | 4 +- ...-prune-producerless-vocabulary-variants.md | 4 +- ...une-producerless-vocabulary-variants.zh.md | 6 +- ...7-04-prune-write-only-fs-surface.i18n.yaml | 4 +- .../2026-07-04-prune-write-only-fs-surface.md | 4 +- ...26-07-04-prune-write-only-fs-surface.zh.md | 6 +- ...-04-remove-agent-steering-mirror.i18n.yaml | 4 +- ...2026-07-04-remove-agent-steering-mirror.md | 4 +- ...6-07-04-remove-agent-steering-mirror.zh.md | 8 +-- ...26-07-04-share-app-bin-boot-glue.i18n.yaml | 4 +- .../2026-07-04-share-app-bin-boot-glue.md | 4 +- .../2026-07-04-share-app-bin-boot-glue.zh.md | 6 +- ...4-tighten-hook-protocol-contract.i18n.yaml | 4 +- ...26-07-04-tighten-hook-protocol-contract.md | 4 +- ...07-04-tighten-hook-protocol-contract.zh.md | 6 +- ...m-acp-bridge-unreachable-surface.i18n.yaml | 4 +- ...-04-trim-acp-bridge-unreachable-surface.md | 4 +- ...-trim-acp-bridge-unreachable-surface.zh.md | 6 +- ...unconsumed-skill-provider-events.i18n.yaml | 4 +- ...2-drop-unconsumed-skill-provider-events.md | 4 +- ...rop-unconsumed-skill-provider-events.zh.md | 6 +- ...-12-prune-unused-web-seam-fields.i18n.yaml | 4 +- ...2026-07-12-prune-unused-web-seam-fields.md | 4 +- ...6-07-12-prune-unused-web-seam-fields.zh.md | 6 +- ...026-06-11-property-based-testing.i18n.yaml | 4 +- .../2026-06-11-property-based-testing.md | 4 +- .../2026-06-11-property-based-testing.zh.md | 4 +- .../2026-06-19-acp-snapshot-tests.i18n.yaml | 4 +- .../testing/2026-06-19-acp-snapshot-tests.md | 4 +- .../2026-06-19-acp-snapshot-tests.zh.md | 2 +- .../2026-06-19-real-api-e2e-ci.i18n.yaml | 4 +- .../testing/2026-06-19-real-api-e2e-ci.md | 4 +- .../testing/2026-06-19-real-api-e2e-ci.zh.md | 6 +- ...e-redundant-snapshot-log-goldens.i18n.yaml | 4 +- ...0-remove-redundant-snapshot-log-goldens.md | 4 +- ...emove-redundant-snapshot-log-goldens.zh.md | 2 +- ...-fork-child-replay-seed-boundary.i18n.yaml | 4 +- ...6-06-22-fork-child-replay-seed-boundary.md | 4 +- ...6-22-fork-child-replay-seed-boundary.zh.md | 6 +- ...26-06-22-fork-snapshot-scenarios.i18n.yaml | 4 +- .../2026-06-22-fork-snapshot-scenarios.md | 4 +- .../2026-06-22-fork-snapshot-scenarios.zh.md | 8 +-- ...6-06-22-subagent-snapshot-replay.i18n.yaml | 4 +- .../2026-06-22-subagent-snapshot-replay.md | 4 +- .../2026-06-22-subagent-snapshot-replay.zh.md | 10 +-- .../2026-07-04-hook-snapshot-matrix.i18n.yaml | 4 +- .../2026-07-04-hook-snapshot-matrix.md | 4 +- .../2026-07-04-hook-snapshot-matrix.zh.md | 14 ++-- ...-single-source-acp-replay-config.i18n.yaml | 4 +- ...6-07-04-single-source-acp-replay-config.md | 4 +- ...7-04-single-source-acp-replay-config.zh.md | 8 +-- ...t-header-content-in-one-scenario.i18n.yaml | 4 +- ...-request-header-content-in-one-scenario.md | 4 +- ...quest-header-content-in-one-scenario.zh.md | 2 +- ...7-08-shared-acp-snapshot-package.i18n.yaml | 4 +- .../2026-07-08-shared-acp-snapshot-package.md | 4 +- ...26-07-08-shared-acp-snapshot-package.zh.md | 6 +- .../2026-06-16-typed-event-schemas.i18n.yaml | 4 +- .../2026-06-16-typed-event-schemas.md | 4 +- .../2026-06-16-typed-event-schemas.zh.md | 8 +-- ...eneric-long-running-tool-runtime.i18n.yaml | 4 +- ...06-20-generic-long-running-tool-runtime.md | 4 +- ...20-generic-long-running-tool-runtime.zh.md | 2 +- ...026-06-30-pre-tool-input-rewrite.i18n.yaml | 4 +- .../2026-06-30-pre-tool-input-rewrite.md | 4 +- .../2026-06-30-pre-tool-input-rewrite.zh.md | 6 +- ...code-and-codex-subagent-backends.i18n.yaml | 4 +- ...claude-code-and-codex-subagent-backends.md | 4 +- ...ude-code-and-codex-subagent-backends.zh.md | 16 ++--- ...-07-08-interactive-side-sessions.i18n.yaml | 4 +- .../2026-07-08-interactive-side-sessions.md | 4 +- ...2026-07-08-interactive-side-sessions.zh.md | 6 +- ...10-sqlite-session-query-provider.i18n.yaml | 4 +- ...026-07-10-sqlite-session-query-provider.md | 4 +- ...-07-10-sqlite-session-query-provider.zh.md | 6 +- ...flow-progress-through-tool-calls.i18n.yaml | 4 +- ...am-workflow-progress-through-tool-calls.md | 4 +- ...workflow-progress-through-tool-calls.zh.md | 6 +- ...2026-06-11-api-extractor-reports.i18n.yaml | 4 +- .../2026-06-11-api-extractor-reports.md | 4 +- .../2026-06-11-api-extractor-reports.zh.md | 6 +- ...-06-11-architectural-conformance.i18n.yaml | 4 +- .../2026-06-11-architectural-conformance.md | 4 +- ...2026-06-11-architectural-conformance.zh.md | 6 +- ...11-supply-chain-and-vendor-drift.i18n.yaml | 4 +- ...026-06-11-supply-chain-and-vendor-drift.md | 4 +- ...-06-11-supply-chain-and-vendor-drift.zh.md | 8 +-- ...06-20-discover-package-inventory.i18n.yaml | 4 +- .../2026-06-20-discover-package-inventory.md | 4 +- ...026-06-20-discover-package-inventory.zh.md | 4 +- ...06-20-unify-agent-and-session-id.i18n.yaml | 4 +- .../2026-06-20-unify-agent-and-session-id.md | 4 +- ...026-06-20-unify-agent-and-session-id.zh.md | 6 +- ...04-prune-dead-core-spine-surface.i18n.yaml | 4 +- ...026-07-04-prune-dead-core-spine-surface.md | 4 +- ...-07-04-prune-dead-core-spine-surface.zh.md | 2 +- ...plify-session-log-representation.i18n.yaml | 4 +- ...-12-simplify-session-log-representation.md | 4 +- ...-simplify-session-log-representation.zh.md | 6 +- ...deterministic-and-stress-testing.i18n.yaml | 4 +- ...-06-11-deterministic-and-stress-testing.md | 4 +- ...-11-deterministic-and-stress-testing.zh.md | 8 +-- .../2026-06-11-mutation-testing.i18n.yaml | 4 +- .../testing/2026-06-11-mutation-testing.md | 4 +- .../testing/2026-06-11-mutation-testing.zh.md | 6 +- ...-06-11-immutable-public-surfaces.i18n.yaml | 4 +- .../2026-06-11-immutable-public-surfaces.md | 4 +- ...2026-06-11-immutable-public-surfaces.zh.md | 8 +-- ...-06-20-providerless-example-base.i18n.yaml | 4 +- .../2026-06-20-providerless-example-base.md | 4 +- ...2026-06-20-providerless-example-base.zh.md | 6 +- ...ssembled-assistant-messages-only.i18n.yaml | 4 +- ...06-20-assembled-assistant-messages-only.md | 4 +- ...20-assembled-assistant-messages-only.zh.md | 6 +- ...2026-06-20-drop-acp-session-load.i18n.yaml | 4 +- .../2026-06-20-drop-acp-session-load.md | 4 +- .../2026-06-20-drop-acp-session-load.zh.md | 6 +- ...026-06-20-drop-acp-terminal-meta.i18n.yaml | 4 +- .../2026-06-20-drop-acp-terminal-meta.md | 4 +- .../2026-06-20-drop-acp-terminal-meta.zh.md | 6 +- ...-20-drop-bash-output-spill-files.i18n.yaml | 4 +- ...2026-06-20-drop-bash-output-spill-files.md | 4 +- ...6-06-20-drop-bash-output-spill-files.zh.md | 6 +- ...-20-drop-durable-step-boundaries.i18n.yaml | 4 +- ...2026-06-20-drop-durable-step-boundaries.md | 4 +- ...6-06-20-drop-durable-step-boundaries.zh.md | 2 +- ...6-20-drop-unused-session-lineage.i18n.yaml | 4 +- .../2026-06-20-drop-unused-session-lineage.md | 4 +- ...26-06-20-drop-unused-session-lineage.zh.md | 6 +- ...ld-session-persistence-interface.i18n.yaml | 4 +- ...6-20-fold-session-persistence-interface.md | 4 +- ...0-fold-session-persistence-interface.zh.md | 2 +- ...026-06-20-generic-tool-rendering.i18n.yaml | 4 +- .../2026-06-20-generic-tool-rendering.md | 4 +- .../2026-06-20-generic-tool-rendering.zh.md | 6 +- ...6-06-20-retire-mid-turn-steering.i18n.yaml | 4 +- .../2026-06-20-retire-mid-turn-steering.md | 4 +- .../2026-06-20-retire-mid-turn-steering.zh.md | 6 +- ...-06-20-single-session-acp-bridge.i18n.yaml | 4 +- .../2026-06-20-single-session-acp-bridge.md | 4 +- ...2026-06-20-single-session-acp-bridge.zh.md | 6 +- ...06-20-truncate-interrupted-turns.i18n.yaml | 4 +- .../2026-06-20-truncate-interrupted-turns.md | 4 +- ...026-06-20-truncate-interrupted-turns.zh.md | 2 +- ...nimplemented-subagent-vocabulary.i18n.yaml | 4 +- ...prune-unimplemented-subagent-vocabulary.md | 4 +- ...ne-unimplemented-subagent-vocabulary.zh.md | 6 +- ...apse-workflow-to-foreground-core.i18n.yaml | 4 +- ...12-collapse-workflow-to-foreground-core.md | 4 +- ...collapse-workflow-to-foreground-core.zh.md | 6 +- ...ne-unused-skill-registry-surface.i18n.yaml | 4 +- ...-12-prune-unused-skill-registry-surface.md | 4 +- ...-prune-unused-skill-registry-surface.zh.md | 6 +- 447 files changed, 1106 insertions(+), 1106 deletions(-) diff --git a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml index 7ddbc75586..fb029f04fe 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-content-block-vocabulary.md: 9414bda624fa6e5fc7e9b11b7a738d32b269af6b -2026-06-11-content-block-vocabulary.zh.md: 764791cbef65c2031b8337af4f4cb6835e9d312a +2026-06-11-content-block-vocabulary.md: 6a90813ec90c6522a88a09d3536ce0cef8250238 +2026-06-11-content-block-vocabulary.zh.md: c9c65ae7e556cdf4eced0d45051862ff87fcd0fe diff --git a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.md b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.md index 9414bda624..6a90813ec9 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.md +++ b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.md @@ -1,9 +1,9 @@ # RFC: Provider-neutral content-block vocabulary owned by dsh-llm -English | [中文](2026-06-11-content-block-vocabulary.zh.md) - Status: implemented +English | [中文](2026-06-11-content-block-vocabulary.zh.md) + ## Problem The harness needs one internal language for messages that the loop, session log, and all plugins speak. diff --git a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md index 764791cbef..c9c65ae7e5 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md @@ -1,4 +1,4 @@ -# RFC:由 dsh-llm 拥有的提供方无关内容块词汇 +# RFC: 由 dsh-llm 拥有的提供方无关内容块词汇 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml index 6e7b3a2125..c08b4133de 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-custom-schema-dsl.md: 4c4d572b15d5e474e00e99fc5e7dd89240251c63 -2026-06-11-custom-schema-dsl.zh.md: eca0428d46ba3b3a4beac0cf9e8f02a9fa198388 +2026-06-11-custom-schema-dsl.md: 34c018b779d45c5eadb7337cb060c43b6f8d09b1 +2026-06-11-custom-schema-dsl.zh.md: 674a6b1a0b67617ffb4ab919899aa108c646a489 diff --git a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.md b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.md index 4c4d572b15..34c018b779 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.md +++ b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.md @@ -1,9 +1,9 @@ # RFC: Custom typed tool-schema DSL instead of schemastery -English | [中文](2026-06-11-custom-schema-dsl.zh.md) - Status: implemented +English | [中文](2026-06-11-custom-schema-dsl.zh.md) + ## Problem Tool parameters must reach the model as standard JSON Schema while giving tool authors typed `execute(args)` without casts. Schemastery already serves plugin config, but the tool-author API needs per-property `required: true` booleans rather than JSON Schema's separate `required` array. diff --git a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md index eca0428d46..674a6b1a0b 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md @@ -1,4 +1,4 @@ -# RFC:使用自定义类型化 tool-schema DSL 替代 schemastery +# RFC: 使用自定义类型化 tool-schema DSL 替代 schemastery Status: implemented @@ -14,7 +14,7 @@ Status: implemented ## 曾考虑的替代方案 -**Schemastery**(已作为 vendor 引入,用于插件 Config)经评估后被否决:它面向的是基于 StandardSchema 的校验/转换,而非 JSON Schema **生成**,因此会增加间接层却无法干净地产出协议格式(wire format)。 +**Schemastery**(已作为 vendor 引入,用于插件 Config)经评估后被否决:它面向的是基于 StandardSchema 的校验/转换,而非 JSON Schema *生成*,因此会增加间接层却无法干净地产出协议格式(wire format)。 ## 后果 diff --git a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml index 0758761505..2df4576e59 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-dev-invariants-over-deep-readonly.md: dc89b5b66d02bde2f4fe2794e04b76ecdeac62ae -2026-06-11-dev-invariants-over-deep-readonly.zh.md: 2c3c9e221b42f4b45216d09e825a41b1be3bcee9 +2026-06-11-dev-invariants-over-deep-readonly.md: 01a9e45fac77d2513924e78566a44a6059dd9d28 +2026-06-11-dev-invariants-over-deep-readonly.zh.md: 8f8db9f5bb095b8fc9c600b741c16d630a6c8167 diff --git a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md index dc89b5b66d..01a9e45fac 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md +++ b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md @@ -1,9 +1,9 @@ # RFC: Source-owned session immutability and dev-mode invariants -English | [中文](2026-06-11-dev-invariants-over-deep-readonly.zh.md) - Status: implemented +English | [中文](2026-06-11-dev-invariants-over-deep-readonly.zh.md) + ## Problem The session log needs two different protections: immutable ownership of each stored fact, and checks for relationships among facts across time and service seams. Conflating them in an optional development plugin would leave production history vulnerable; trying to express both through TypeScript readonly types would not create a runtime boundary or describe relational rules. diff --git a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md index 2c3c9e221b..8f8db9f5bb 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md @@ -1,4 +1,4 @@ -# RFC:源端拥有的会话不可变性与开发模式不变式 +# RFC: 源端拥有的会话不可变性与开发模式不变式 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml index e7645f5f8d..747bbf3ab0 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-event-sourced-sessions.md: 04ff974826ffbc9052c7eb9f5794bc16557241f9 -2026-06-11-event-sourced-sessions.zh.md: 12d6aedcc32b4d93f0dbe010854bcd3a0721703f +2026-06-11-event-sourced-sessions.md: c1460b84c5928a53537a5f6a51f41c4d5b101a12 +2026-06-11-event-sourced-sessions.zh.md: 938404524cd23a5a5b3d6d0b7fd5020df3d35a51 diff --git a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.md b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.md index 04ff974826..c1460b84c5 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.md +++ b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.md @@ -1,9 +1,9 @@ # RFC: Event-sourced sessions with derived message history -English | [中文](2026-06-11-event-sourced-sessions.zh.md) - Status: implemented +English | [中文](2026-06-11-event-sourced-sessions.zh.md) + ## Problem The MVP requires strict event-based tracing with fully replayable sessions (严格的基于事件的trace、logging系统,session完全可回放). diff --git a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md index 12d6aedcc3..938404524c 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md @@ -1,9 +1,9 @@ -# RFC:事件溯源的会话与派生消息历史 - -[English](2026-06-11-event-sourced-sessions.md) | 中文 +# RFC: 事件溯源的会话与派生消息历史 Status: implemented +[English](2026-06-11-event-sourced-sessions.md) | 中文 + ## 问题 MVP 要求严格的基于事件的追踪,以及完全可回放的会话(严格的基于事件的 trace、logging 系统,session 完全可回放)。 @@ -14,7 +14,7 @@ MVP 要求严格的基于事件的追踪,以及完全可回放的会话(严 追加操作是同步的(热路径从不阻塞于 I/O);`session/event` 是同步通知;持久化插件在后台缓冲写入,并在每个轮次结束时触发的 `session/flush` 检查点处等待排空。 -顺序契约:agent loop(智能体循环)先追加到会话,再发出对应的 Cordis 事件;`agent/step-result` waterfall(瀑布式事件)在 `assistant/message` 追加之前运行,因此日志记录的是工具调度实际使用的消息。回归测试固定了这一顺序。 +顺序契约:agent loop(智能体循环)*先*追加到会话,再发出对应的 Cordis 事件;`agent/step-result` waterfall(瀑布式事件)在 `assistant/message` 追加之前运行,因此日志记录的是工具调度实际使用的消息。回归测试固定了这一顺序。 ## 曾考虑的替代方案 diff --git a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml index 8634a86f36..107aab3c75 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-microkernel-event-taxonomy.md: c66968257a5a6304f187ccb5b9a162aa143e608d -2026-06-11-microkernel-event-taxonomy.zh.md: 7becf5872aee16fe21b4acbbc61920ed91c40f44 +2026-06-11-microkernel-event-taxonomy.md: 47e363f949b506756d9b20ee7dc53ca81e3f5e4d +2026-06-11-microkernel-event-taxonomy.zh.md: 3b0aa54108bf8737e6fe341c7b0797a554d328ec diff --git a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.md b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.md index c66968257a..47e363f949 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.md +++ b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.md @@ -1,9 +1,9 @@ # RFC: Microkernel — extension via Cordis event taxonomy, one concrete loop -English | [中文](2026-06-11-microkernel-event-taxonomy.zh.md) - Status: implemented +English | [中文](2026-06-11-microkernel-event-taxonomy.zh.md) + ## Problem The product principle is "everything is a plugin": hooks, /goal, /loop, dynamic workflows, compaction, sandboxing, permissions, UI, persistence, MCP, skills must all be writable as plugins without modifying the core. diff --git a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md index 7becf5872a..3b0aa54108 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md @@ -1,4 +1,4 @@ -# RFC:微内核——通过 Cordis 事件分类体系实现扩展,唯一具体循环 +# RFC: 微内核——通过 Cordis 事件分类体系实现扩展,唯一具体循环 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml index 9ae6b5d602..0fa22e5594 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-runtime-arg-validation.md: 6da117643166d304bee1d368a314cc1602cac828 -2026-06-11-runtime-arg-validation.zh.md: 5f41ff99a2d56f39ff8d61191d92dc782f163c82 +2026-06-11-runtime-arg-validation.md: 82d01263225ce719e80631d1890f0a6cc328119d +2026-06-11-runtime-arg-validation.zh.md: 4bd6720f7ec87fcef028ba94f445a5210f1b0d7a diff --git a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.md b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.md index 6da1176431..82d0126322 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.md +++ b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.md @@ -1,9 +1,9 @@ # RFC: Runtime arg validation at the model boundary -English | [中文](2026-06-11-runtime-arg-validation.zh.md) - Status: implemented +English | [中文](2026-06-11-runtime-arg-validation.zh.md) + ## Problem `defineTool` ([the custom schema DSL](2026-06-11-custom-schema-dsl.md)) gives tool authors a typed `execute(args)` via the `InferArgs` mapping. But that type is a compile-time claim about a value that arrives at runtime as model-generated JSON: nothing forced the model to honor the schema, so a malformed call — missing a required key, a string where a number was declared, an enum value outside the set — reached `execute` typed-in-name-only. The tool body then either crashed on the bad shape (a generic stack trace the model can't act on) or, worse, silently misbehaved. Meanwhile the converter already encodes the exact structure a validator would need to walk. diff --git a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md index 5f41ff99a2..4bd6720f7e 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md @@ -1,4 +1,4 @@ -# RFC:模型边界处的运行时参数校验 +# RFC: 模型边界处的运行时参数校验 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml index aa6cdb26ff..4a381ba271 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-structured-error-taxonomy.md: 2baf88a1f942215e79561e565f455276c80178c4 -2026-06-11-structured-error-taxonomy.zh.md: 90b0fdd7f6c8b4f0565c6538c2ddd4cb31680c38 +2026-06-11-structured-error-taxonomy.md: 5a5f75038b6124457d2d4d08cbe0bec80415a387 +2026-06-11-structured-error-taxonomy.zh.md: d5a45a447ca00d48cb8366911a10f34c584d915c diff --git a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.md b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.md index 2baf88a1f9..5a5f75038b 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.md +++ b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.md @@ -1,9 +1,9 @@ # RFC: Structured error taxonomy -English | [中文](2026-06-11-structured-error-taxonomy.zh.md) - Status: implemented +English | [中文](2026-06-11-structured-error-taxonomy.zh.md) + ## Problem Failures crossed seams as bare strings. A tool error flattened to a text block — name, code, and stack lost — so a future sandbox/retry plugin couldn't tell ENOENT from EACCES, and the model got less actionable feedback than it could. A non-Error throw degraded further: the loop wrapped it in `new Error(String(x))`, dropping any code. And `LlmError` was the only typed error in the system, with no shared base, so there was nothing for a consumer to `instanceof` against generically. diff --git a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md index 90b0fdd7f6..d5a45a447c 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md @@ -1,4 +1,4 @@ -# RFC:结构化错误分类体系 +# RFC: 结构化错误分类体系 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml index 5f5b2ef266..57fe989a5d 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-tool-schemas-in-prompt-assembly.md: 443e6f20115e5a76001b4466c2d756675adbd886 -2026-06-11-tool-schemas-in-prompt-assembly.zh.md: 03624b98fabdedf691f3fb448cc5f37ba5a649ef +2026-06-11-tool-schemas-in-prompt-assembly.md: 260d56ffab054d874e13eb34eac029bf59b381fc +2026-06-11-tool-schemas-in-prompt-assembly.zh.md: 5ae98dfac676574d00f34580ec079bb6a8f2331f diff --git a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md index 443e6f2011..260d56ffab 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md +++ b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md @@ -1,9 +1,9 @@ # RFC: Tool schemas are part of the system-prompt assembly -English | [中文](2026-06-11-tool-schemas-in-prompt-assembly.zh.md) - Status: implemented +English | [中文](2026-06-11-tool-schemas-in-prompt-assembly.zh.md) + ## Problem On the wire, tool schemas travel in a dedicated `tools` field of the model request, not in prompt text. Architecturally, though, "what the model is told it can do" is one coherent concern: prompt sections and the tool list are assembled from the same plugin contributions and consumed at the same moment. diff --git a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md index 03624b98fa..5ae98dfac6 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md @@ -1,4 +1,4 @@ -# RFC:工具 schema 是系统提示词组装的一部分 +# RFC: 工具 schema 是系统提示词组装的一部分 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.i18n.yaml index d0eac81287..fcdc63390f 100644 --- a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-13-capability-seams.md: e9d417dbd2bafcaece39601b12dbb310feb1e19b -2026-06-13-capability-seams.zh.md: c569f3df083ec48bd05e6be2d3a1e5875fde362f +2026-06-13-capability-seams.md: f10182737347fc54ff3fd06edb299e569397773d +2026-06-13-capability-seams.zh.md: e65d2f31eb80ce80e92b3e4bbb4d5b8948185c44 diff --git a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.md b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.md index e9d417dbd2..f101827373 100644 --- a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.md +++ b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.md @@ -1,9 +1,9 @@ # RFC: Capability seams — interface / implementation / consumer split -English | [中文](2026-06-13-capability-seams.zh.md) - Status: implemented +English | [中文](2026-06-13-capability-seams.zh.md) + ## Problem The harness has swappable capabilities — bash execution today, sandboxed/remote executors and alternative model providers tomorrow. A capability has three concerns that change at different rates and for different reasons: the *contract* (what the capability is), the *implementation* (how it runs), and the *consumer surface* (what the model and other plugins program against). Bundling them in one package couples those rates of change — swapping a local executor for a sandboxed one would churn the tool schemas the model sees, even though the model-facing contract never changed. diff --git a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.zh.md b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.zh.md index c569f3df08..e65d2f31eb 100644 --- a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.zh.md @@ -1,9 +1,9 @@ -# RFC:能力 seam——接口/实现/消费方三分 - -[English](2026-06-13-capability-seams.md) | 中文 +# RFC: 能力 seam——接口/实现/消费方三分 Status: implemented +[English](2026-06-13-capability-seams.md) | 中文 + ## 问题 harness 具有可替换的能力:当前是 bash 执行,未来会有沙箱化/远程执行器和替代模型提供方。一项能力涉及三个关注点,它们以不同速率、因不同原因变化:*契约*(这项能力是什么)、*实现*(它如何运行)、*消费方接口*(模型和其他插件面向什么编程)。将三者捆绑在一个包(package)中会耦合这些变化速率——把本地执行器换成沙箱化执行器时,模型看到的工具 schema 也会被搅动,尽管面向模型的契约从未改变。 @@ -25,7 +25,7 @@ harness 具有可替换的能力:当前是 bash 执行,未来会有沙箱化 ## 曾考虑的替代方案 - **单一合并包**:否决。因为它重新耦合了三分设计本要分离的三种变化速率(这正是拆分的意义所在)。 -- **`@cordisjs/plugin-capability`**:这是完全不同的维度。它是一个权限/能力*安全*服务(具名权限加继承,通过 `ctx.capability.test` 对会话进行检测),是延后的权限/沙箱工作(`tools/pre-execute` deny/ask seam)的候选方案,**不是**替换实现的机制。混淆这两个「能力」概念正是本 RFC 所指出的陷阱。 +- **`@cordisjs/plugin-capability`**:这是完全不同的维度。它是一个权限/能力*安全*服务(具名权限加继承,通过 `ctx.capability.test` 对会话进行检测),是延后的权限/沙箱工作(`tools/pre-execute` deny/ask seam)的候选方案,不是替换实现的机制。混淆这两个「能力」概念正是本 RFC 所指出的陷阱。 ## 后果 diff --git a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml index df04a14d6a..545aae3758 100644 --- a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-13-twin-llm-adapters.md: 4efefcf4e2f6b1d60567ba3bfed7ae1ea53a7a4e -2026-06-13-twin-llm-adapters.zh.md: 6cabd95c5361afdea5b33ffdee34a5acb6026f7f +2026-06-13-twin-llm-adapters.md: edd7080e2a16e9f1af2ebd56a4265040dc970c17 +2026-06-13-twin-llm-adapters.zh.md: 2087d498f65326fa0a2cb74be409a926a5e343f5 diff --git a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.md b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.md index 4efefcf4e2..edd7080e2a 100644 --- a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.md +++ b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.md @@ -1,9 +1,9 @@ # RFC: Two LLM adapters as a design-verification twin -English | [中文](2026-06-13-twin-llm-adapters.zh.md) - Status: implemented +English | [中文](2026-06-13-twin-llm-adapters.zh.md) + ## Problem `dsh-llm` owns a provider-neutral streaming vocabulary — the `StreamChunk` protocol (`block-start`, `text-delta`, `reasoning-delta`, `tool-call-delta`, `block-end`, `usage`, `finish`) and the content-block types ([the content-block vocabulary](2026-06-11-content-block-vocabulary.md)). A vocabulary defined against a single adapter risks baking that adapter's quirks into the "neutral" contract: anything the one implementation happens to do becomes the de-facto spec, and the abstraction is unverified until a second provider arrives — by which point the leak is expensive to fix. diff --git a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md index 6cabd95c53..2087d498f6 100644 --- a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md @@ -1,4 +1,4 @@ -# RFC:以两个 LLM 适配器作为设计验证孪生体 +# RFC: 以两个 LLM 适配器作为设计验证孪生体 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.i18n.yaml index c6b9eaf967..aa7fe88f24 100644 --- a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-14-session-persistence.md: 4078487b71862791dd25cf2afcfc03255cfeb0be -2026-06-14-session-persistence.zh.md: a44ef9647ca4003bc81023a54b7e9b5945003b02 +2026-06-14-session-persistence.md: a50c076746981892239304266194d1e8e309574f +2026-06-14-session-persistence.zh.md: d609e663bd9e36f74bf34404c021a30f54d3bd76 diff --git a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.md b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.md index 4078487b71..a50c076746 100644 --- a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.md +++ b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.md @@ -1,9 +1,9 @@ # RFC: Session persistence as an abstract service over the existing `SessionEvent` -English | [中文](2026-06-14-session-persistence.zh.md) - Status: implemented +English | [中文](2026-06-14-session-persistence.zh.md) + ## Problem Sessions lived only in memory. The example `session-jsonl.ts` plugin (duplicated byte-for-byte in both examples) was write-only telemetry: it buffered `session/event` and appended JSON lines, with no read/replay path, no crash-safety (no fsync, no atomic write, a fire-and-forget dispose drain), no listing, and no format versioning. Nothing could rehydrate a past session from disk into a live agent, so durable resume ("continue yesterday's task"), durable forking, and the ACP `session/load` method ([ACP support](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md)) were all impossible. diff --git a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.zh.md b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.zh.md index a44ef9647c..d609e663bd 100644 --- a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.zh.md @@ -1,4 +1,4 @@ -# RFC:会话持久化作为基于现有 `SessionEvent` 的抽象服务 +# RFC: 会话持久化作为基于现有 `SessionEvent` 的抽象服务 Status: implemented @@ -23,7 +23,7 @@ Status: implemented - **仅追加;崩溃的轮次被关闭,而非截断。** 已刷写到 `turn/end` 的事件永不被重写,且循环仅在轮次结束时刷写。由于一个被中断的轮次可能包含大量有效工作,`load` 保留其连续、可解析的事件,并为未应答的工具调用追加错误结果、补一个缺失的 `step/end`,以及带 `{ kind: 'interrupted' }` 的 `turn/end`。合成的结果保证恢复后的 provider transcript(文本记录)仍然有效。只有不完整的最后一条记录会被丢弃;在最后一个真实 `turn/end` 处或之前出现解析错误或序号间隙,属于数据损坏,会使该会话不可加载。 - **文件后端为规范实现,数据库后端为经过验证的直接替换。** `SessionEvent` 1:1 映射到一行 `(session_id, seq, type, time, data)`:`append` 是 INSERT(在一个断言连续 seq 契约的事务中),`load` 是 SELECT … ORDER BY seq。`dsh-session-persistence-sqlite` 正是如此:一个 `SessionPersistence` 子类,接口无变化(opencode 在 SQLite/WAL 上运行的正是这个形状),且通过与 JSONL 后端相同的 `runPersistenceContract` 测试套件。该契约以相同的语义约束两个后端(惰性物化、加载时关闭中断轮次、连续 seq),一次表达在文件字节上,一次表达在数据库行上。 - **元数据在日志之外。** 格式版本、cwd 和谱系是存储关注点,不是可回放的对话状态,因此它们存放在 `dsh-session` 拥有的 `SessionHeader` 中,并通过新的只读属性 `session.header` 附加到 `Session` 上——永远不进入 `SessionEventMap`,永远不到达 `deriveMessages()`。替代方案(一个可合并扩展的 `session/meta` 事件作为日志第 0 行)被否决:日志内事件会随 seed/fork 的会话免费携带,但元数据不是可回放状态,因此显式的日志外 header seam 是更干净的代价。(header 最初被拆分为不可变的 `SessionHeader` 加可变的 `SessionSummary`,二者的联合类型为 `SessionMeta`;可变 summary 后来因属于死状态而被移除——见 [移除可变会话摘要](../simplification/2026-06-19-drop-mutable-session-summary.md)。) -- **`ctx.agents.create()` 和 `ctx.agents.resume()` 是异步工厂;resume 还跨越持久化边界。** `ctx.agents.resume({ resumeSessionId })` 等待 `ctx.sessionPersistence.load`,用加载的事件重建活跃会话(使 `lastTurnNumber`/`deriveMessages` 得以延续),并在恢复的 id 上启动一个新 agent(不是 `${agentId}-session`)。agent loop(智能体循环)不会硬注入 `sessionPersistence`(那样会让非持久化的演示永远挂起);当 `sessionPersistence` 不存在时,`resume` 以明确的错误拒绝。 +- **`ctx.agents.create()` 和 `ctx.agents.resume()` 是异步工厂;resume 还跨越持久化边界。** `ctx.agents.resume({ resumeSessionId })` 等待 `ctx.sessionPersistence.load`,用加载的事件重建活跃会话(使 `lastTurnNumber`/`deriveMessages` 得以延续),并在恢复的 id 上启动一个新 agent(不是 `${agentId}-session`)。agent loop(智能体循环)不会硬注入 `sessionPersistence`(那样会让非持久化的演示永远挂起);当它不存在时,`resume` 以明确的错误拒绝。 ## 曾考虑的替代方案 diff --git a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml index 72eb9e3d7a..cf8898285a 100644 --- a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-15-turn-enclosure-invariant.md: bf0789f21ba7bd928e023bb5fd844d9ec78c4bc1 -2026-06-15-turn-enclosure-invariant.zh.md: 644e7b975e024286d5307f586f509c2b4a9f21ea +2026-06-15-turn-enclosure-invariant.md: 26ae1890e481288b3be17f97db14c332f69be4b8 +2026-06-15-turn-enclosure-invariant.zh.md: 1946f829100e39afed826b8cf3ba82d22058c27d diff --git a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md index bf0789f21b..26ae1890e4 100644 --- a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md +++ b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md @@ -1,9 +1,9 @@ # RFC: Every session event is enclosed in a turn -English | [中文](2026-06-15-turn-enclosure-invariant.zh.md) - Status: implemented +English | [中文](2026-06-15-turn-enclosure-invariant.zh.md) + ## Problem A durable session-persistence backend (added in a companion change) uses the **turn** as its crash-recovery boundary: a crash can leave an unclosed final turn, which `load` closes with a synthetic `turn/end {kind:'interrupted'}` while preserving the turn's real events (see [session persistence](2026-06-14-session-persistence.md)). This recovery is only well-defined if nothing *legitimately* durable sits OUTSIDE a turn — between the last `turn/end` and the next `turn/start` — since such an event would be swept into the next turn's interrupted close. diff --git a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md index 644e7b975e..1946f82910 100644 --- a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md @@ -1,4 +1,4 @@ -# RFC:每个会话事件都封闭在一个轮次内 +# RFC: 每个会话事件都封闭在一个轮次内 Status: implemented @@ -10,7 +10,7 @@ Status: implemented 这一假设并不成立。有两条路径在任何轮次之外记录了事件: -1. **排队的用户消息。** agent loop(智能体循环)排空排队消息并在 `turn/start` **之前**追加 `user/message`——于是一个轮次自身的提示词落在了前一个 `turn/end` 与下一个 `turn/start` 之间的间隙中。 +1. **排队的用户消息。** agent loop(智能体循环)排空排队消息并在 `turn/start` *之前*追加 `user/message`——于是一个轮次自身的提示词落在了前一个 `turn/end` 与下一个 `turn/start` 之间的间隙中。 2. **空闲时的上下文注入。** `agent.inject()` 直接追加一条 `context/message`。它在生产环境中的真实调用方是 `dsh-tool-bash`,后者从 `ctx.bash.onTaskDone` 注入后台任务完成通知——该回调在后台 bash 任务完成时触发,而这经常发生在 agent **空闲**(轮次之间)时。 在情况 2 中,如果注入的 `context/message` 是 flush/dispose 之前的最后一个事件(之后没有轮次追加 `turn/end`),`scanLog` 会将其视为崩溃残留并在**恢复时丢弃**——注入的上下文已持久写入磁盘,但重新加载后被静默丢失。情况 1 本身无害(`user/message` 之后总会跟着它触发的轮次),但使「什么可以出现在轮次之外」这条规则变得模糊。 diff --git a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml index 11faf45d26..62ab944e40 100644 --- a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-17-filesystem-capability-seam.md: c502ae712de22e97661192057d4410c7c55ea044 -2026-06-17-filesystem-capability-seam.zh.md: 4e544e24c548a52bde254886a65ff2fdb559a986 +2026-06-17-filesystem-capability-seam.md: c87c8a44d2e956a9613039378d26f72e8ee97ee7 +2026-06-17-filesystem-capability-seam.zh.md: 4864e77ced5c078fc8c1e970a2ff88c78a37af2a diff --git a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.md b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.md index c502ae712d..c87c8a44d2 100644 --- a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.md +++ b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.md @@ -1,9 +1,9 @@ # RFC: Filesystem capability seam — ctx.fs, local backend, and model-facing filesystem tools -English | [中文](2026-06-17-filesystem-capability-seam.zh.md) - Status: implemented +English | [中文](2026-06-17-filesystem-capability-seam.zh.md) + ## Problem The harness has a concrete `bash` capability seam (`dsh-bash` / `dsh-bash-local` / `dsh-tool-bash`), but filesystem operations are about to be added as model-facing tools without an equivalent seam. If `read`, `write`, and `edit` directly use `node:fs`, the model-facing tool package will own filesystem execution policy, local path resolution, atomic write behavior, text decoding, symlink behavior, and edit semantics all at once. diff --git a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md index 4e544e24c5..4864e77ced 100644 --- a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md @@ -1,9 +1,9 @@ -# RFC:文件系统能力 seam——ctx.fs、本地后端与面向模型的文件系统工具 - -[English](2026-06-17-filesystem-capability-seam.md) | 中文 +# RFC: 文件系统能力 seam——ctx.fs、本地后端与面向模型的文件系统工具 Status: implemented +[English](2026-06-17-filesystem-capability-seam.md) | 中文 + ## 问题 harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` / `dsh-tool-bash`),但文件系统操作即将作为面向模型的工具加入,却没有等价的 seam。如果 `read`、`write` 和 `edit` 直接使用 `node:fs`,面向模型的工具包将同时承担文件系统执行策略、本地路径解析、原子写入行为、文本解码、符号链接行为和编辑语义。 @@ -80,10 +80,10 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` 解析后的目标必须至少暴露三个概念: - 原始输入路径,用于诊断。 -- 不透明的 `targetKey`,用于过期守护和文件状态查找。本地后端可能使用类似 realpath 的键;远程后端可能使用工作区 URI 或文件 id。消费方禁止解析或假设它是本地绝对路径。 +- 不透明的 `targetKey`,用于陈旧守护和文件状态查找。本地后端可能使用类似 realpath 的键;远程后端可能使用工作区 URI 或文件 id。消费方禁止解析或假设它是本地绝对路径。 - `displayPath`,用于面向模型/UI 的输出。根据后端不同,它可能是本地绝对路径、工作区相对路径或远程 URI。 -读取和变更结果必须包含不透明的文件 `version`。本地后端可以使用 mtime/size 或类似 hash 的令牌;远程后端可以使用 revision id。`dsh-fs-policy` 插件记录版本用于过期检查;消费方可以展示相关元数据但禁止解释版本令牌。 +读取和变更结果必须包含不透明的文件 `version`。本地后端可以使用 mtime/size 或类似 hash 的令牌;远程后端可以使用 revision id。`dsh-fs-policy` 插件记录版本用于陈旧检查;消费方可以展示相关元数据但禁止解释版本令牌。 提供方返回已解码的文本:`readText` 返回整个常规文本文件,`streamText` 为大文件流式传输相同的文本语义。两者负责常规文件检查;有界的行/输出处理不是它们的职责——行窗口化、带行号渲染和总行数统计位于执行器(`dsh-tool-fs`)中,执行器通过 `ctx.fs` 读取并渲染面向模型的窗口。提供方负责 UTF-8 解码和二进制/NUL 拒绝;它不知道行窗口或视图。 @@ -91,7 +91,7 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` 全文件写入创建或替换 UTF-8 文本文件。后端在支持且有文档说明时可以创建父目录。已有的非常规目标被拒绝。`writeText` 接受一个可选期望:`createIfAbsent` 创建缺失的目标并拒绝已存在的(报 `FS_NOT_OBSERVED`,这是策略为未观测 owner 使用的路径);`replaceIfVersion` 仅在目标处于观测版本时替换,否则报 `FS_STALE_VERSION`;省略期望则为无条件的裸提供方创建或覆盖。策略插件根据 owner 的观测状态选择提供哪个期望。 -字面编辑是提供方原语(`editText`),而非在 `tool-fs` 中由读取加写入组合而成。字面匹配、重复匹配拒绝、CRLF 保留、二进制拒绝、可选的过期版本检查和原子读-改-写必须一起留在后端的变更临界区内。`editText` 接受相同的可选版本期望;过期检查在字面匹配之前运行,因此基于旧读取的编辑会报 `FS_STALE_VERSION`。远程后端可以将编辑实现为原生的 compare-and-edit 操作;消费方不强制本地风格的组合。 +字面编辑是提供方原语(`editText`),而非在 `tool-fs` 中由读取加写入组合而成。字面匹配、重复匹配拒绝、CRLF 保留、二进制拒绝、可选的陈旧版本检查和原子读-改-写必须一起留在后端的变更临界区内。`editText` 接受相同的可选版本期望;陈旧检查在字面匹配之前运行,因此基于旧读取的编辑会报 `FS_STALE_VERSION`。远程后端可以将编辑实现为原生的 compare-and-edit 操作;消费方不强制本地风格的组合。 策略插件(而非 `ctx.fs`)对先前观测进行门控:`edit` 要求 owner 有先前观测(否则报 `FS_NOT_OBSERVED`),记录的版本作为 CAS 基础传给 `editText`。在策略插件缺席时,`ctx.fs` 本身是一个完整的无约束 seam(无条件写入/编辑);工具从不与策略方法耦合。 @@ -129,8 +129,8 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` 本仓库曾踩过的防御性模式类别被直接固定: - **原子写入临时文件安全。** 写入/编辑通过目标旁边一个私有随机 `0700` 目录中的独占 owner-only(`'wx'`、`0o600`)临时文件暂存,失败时清理,最后原子 rename——与 bash 溢出文件规则一致,因为可预测的 world-readable 临时路径招致符号链接竞争和信息泄露。测试断言权限,并断言已存在的临时路径不会被覆盖;此原语是 seam 的常设要求。 -- **通过符号链接的 `targetKey` 同一性。** 两个输入路径解析到同一 realpath 时共享一个观测状态条目:通过路径 A 的 `read` 满足通过符号链接路径 B 的 `edit` 的读后编辑守护,通过一个路径的过期写入可通过另一个路径检测到。 -- **并发/过期竞争。** 对同一目标的两个并发写入/编辑操作确定性地收敛——一个成功,另一个被 `FS_STALE_VERSION` 拒绝——成功的编辑刷新记录状态,使同一 owner 的下一次编辑可以继续。 +- **通过符号链接的 `targetKey` 同一性。** 两个输入路径解析到同一 realpath 时共享一个观测状态条目:通过路径 A 的 `read` 满足通过符号链接路径 B 的 `edit` 的读后编辑守护,通过一个路径的陈旧写入可通过另一个路径检测到。 +- **并发/陈旧竞争。** 对同一目标的两个并发写入/编辑操作确定性地收敛——一个成功,另一个被 `FS_STALE_VERSION` 拒绝——成功的编辑刷新记录状态,使同一 owner 的下一次编辑可以继续。 - **HMR(热模块替换)安全与 dispose(资源释放)。** dispose 后端的 fiber 会撤回 `ctx.fs` 提供方;后续的提供方以无继承状态启动。 ## 曾考虑的替代方案 @@ -155,6 +155,6 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` **观测状态持久化被推迟。** 观测状态存在于内存中(`dsh-fs-policy` 内部的 `WeakMap`),因此恢复的会话保守地要求文件在写入/编辑前重新读取,直到未来的会话事件或持久化机制使观测可回放。 -**错误码成为 seam 的一部分。** `FsError` 错误码使过期版本和观测失败可通过既有的结构化错误分类体系进行机器路由。代价是 `dsh-fs` 从 `dsh-llm` 导入共享的 `HarnessError` 基类;该依赖是有意为之且限于错误词汇。 +**错误码成为 seam 的一部分。** `FsError` 错误码使陈旧版本和观测失败可通过既有的结构化错误分类体系进行机器路由。代价是 `dsh-fs` 从 `dsh-llm` 导入共享的 `HarnessError` 基类;该依赖是有意为之且限于错误词汇。 **包拆分的成本前置。** 三包拆分在只有一个后端时就增加了样板代码。这是有意为之:文件系统访问是可能的沙箱/远程边界,在面向模型的工具发布后再改包接口代价更高。 diff --git a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml index 27f4b260ae..34098ed665 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-18-agent-lifecycle-and-ownership-seams.md: a70e7db8d809efd68ae770995795fc7b3d1b83d2 -2026-06-18-agent-lifecycle-and-ownership-seams.zh.md: 3fb68336c56b5296f18b3587ea42399a05362733 +2026-06-18-agent-lifecycle-and-ownership-seams.md: c37578020366dd40250c061e34a86d2de6907e19 +2026-06-18-agent-lifecycle-and-ownership-seams.zh.md: 1f3cb609da5508d22046f445e08a75dc5a7901cd diff --git a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md index a70e7db8d8..c375780203 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md +++ b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md @@ -1,9 +1,9 @@ # RFC: Agent lifecycle and ownership seams -English | [中文](2026-06-18-agent-lifecycle-and-ownership-seams.zh.md) - Status: implemented +English | [中文](2026-06-18-agent-lifecycle-and-ownership-seams.zh.md) + ## Problem Several ACP and tool-bash limitations were symptoms of the same missing seam: plugins could create or resume agents through `ctx.agents`, but they could not own and dispose one agent independently, and long-running bash tasks carried no stable owner in the executor itself. ACP aborted and awaited agents on disconnect but could not unregister just that session's agent; `session/cancel` could not cancel queued-but-not-yet-started work; and `tool-bash` kept task ownership in a plugin-local `Map`, so an HMR reload could make an old task look unowned. diff --git a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md index 3fb68336c5..1f3cb609da 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md @@ -1,9 +1,9 @@ -# RFC:Agent 生命周期与所有权 seam - -[English](2026-06-18-agent-lifecycle-and-ownership-seams.md) | 中文 +# RFC: Agent 生命周期与所有权 seam Status: implemented +[English](2026-06-18-agent-lifecycle-and-ownership-seams.md) | 中文 + ## 问题 ACP(Agent Client Protocol)与 tool-bash 的若干限制是同一个缺失 seam 的症状:插件可以通过 `ctx.agents` 创建或恢复 agent(智能体),但无法独立拥有和 dispose(资源释放)单个 agent,而长时间运行的 bash 任务在执行器中也没有稳定的所有者。ACP 在断连时中止并等待 agent,却无法仅注销该会话的 agent;`session/cancel` 无法取消已入队但尚未开始的工作;`tool-bash` 将任务所有权保存在插件本地的 `Map` 中,因此一次 HMR(热模块替换)重载就可能让旧任务看起来无主。 diff --git a/docs/rfc/implemented/architecture/2026-06-18-session-surface.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-18-session-surface.i18n.yaml index 98b4ee0e59..c319a372fe 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-session-surface.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-18-session-surface.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-18-session-surface.md: 31297166b735468147850a81d7fd43a8fa30a1e8 -2026-06-18-session-surface.zh.md: 159aefc10261ac5380701f46c3d4a367674940b1 +2026-06-18-session-surface.md: bcad236eaa2bead3c140e7a12772729710d43f83 +2026-06-18-session-surface.zh.md: 2ec60501c183d1bdab22ceb67b7f6aa0040ae82b diff --git a/docs/rfc/implemented/architecture/2026-06-18-session-surface.md b/docs/rfc/implemented/architecture/2026-06-18-session-surface.md index 31297166b7..bcad236eaa 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-session-surface.md +++ b/docs/rfc/implemented/architecture/2026-06-18-session-surface.md @@ -1,9 +1,9 @@ # RFC: Session surface — a linked list over the event log for LLM message derivation -English | [中文](2026-06-18-session-surface.zh.md) - Status: implemented +English | [中文](2026-06-18-session-surface.zh.md) + ## Problem The event log is authoritative, but history manipulation had no durable shared mechanism. Plugins such as compaction would otherwise rewrite derived requests through order-sensitive listeners, leave no provenance, and require repeated changes to `deriveMessages()`. diff --git a/docs/rfc/implemented/architecture/2026-06-18-session-surface.zh.md b/docs/rfc/implemented/architecture/2026-06-18-session-surface.zh.md index 159aefc102..2ec60501c1 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-session-surface.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-18-session-surface.zh.md @@ -1,9 +1,9 @@ -# RFC:会话 surface——基于事件日志的链表,用于 LLM 消息派生 - -[English](2026-06-18-session-surface.md) | 中文 +# RFC: 会话 surface——基于事件日志的链表,用于 LLM 消息派生 Status: implemented +[English](2026-06-18-session-surface.md) | 中文 + ## 问题 事件日志是权威数据源,但历史操纵此前没有持久化的共享机制。如果没有这样的机制,上下文压缩(context compaction)等插件只能通过顺序敏感的监听器改写派生请求,不留溯源信息,且每次新增操纵都要反复修改 `deriveMessages()`。 diff --git a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml index f693539b91..e960781d12 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-18-shared-persistence-write-coordinator.md: 3fc30dc2e1382fd983d050433123f46a2cd0ed19 -2026-06-18-shared-persistence-write-coordinator.zh.md: 38e900d38cc48317836717ddeda5323cf97df993 +2026-06-18-shared-persistence-write-coordinator.md: 7648c6f8e43fb8c78f881838aa4d476aba209dca +2026-06-18-shared-persistence-write-coordinator.zh.md: 19f583c2f3d78fcdac1378cfe00e49c0be943eb1 diff --git a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md index 3fc30dc2e1..7648c6f8e4 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md +++ b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md @@ -1,9 +1,9 @@ # RFC: Shared persistence write coordinator -English | [中文](2026-06-18-shared-persistence-write-coordinator.zh.md) - Status: implemented +English | [中文](2026-06-18-shared-persistence-write-coordinator.zh.md) + ## Problem `dsh-session-persistence-jsonl` and `dsh-session-persistence-sqlite` intentionally prove the same `SessionPersistence` contract over different storage media, but their write-path orchestration was duplicated: per-session state, `session/created` adoption, backend-specific prefix reads, write-behind buffers, serialized flush chains, HMR seeding, and dispose drains. The pure seed-prefix collision and serializability guards had already moved into the seam package; the remaining orchestration was still correctness-heavy and received the same fixes twice. A code-level diff showed the two backends were byte-identical — or same-algorithm — for ALL of it: the four maps (`states`/`buffers`/`chains`/`inits`), `installWritePath`, `initFor`, `onCreated`'s four cases, `flush`, `drain`, `serialize`, `adopt`, `adoptLivePrefix`, `assertVersion`, and the `create`/`append`/`load` skeletons. Only the storage primitives (write bytes vs. INSERT rows) differed. diff --git a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md index 38e900d38c..19f583c2f3 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md @@ -1,12 +1,12 @@ -# RFC:共享持久化写入协调器 - -[English](2026-06-18-shared-persistence-write-coordinator.md) | 中文 +# RFC: 共享持久化写入协调器 Status: implemented +[English](2026-06-18-shared-persistence-write-coordinator.md) | 中文 + ## 问题 -`dsh-session-persistence-jsonl` 与 `dsh-session-persistence-sqlite` 有意在不同存储介质上证明同一份 `SessionPersistence` 契约,但它们的写入路径编排是重复的:per-session 状态、`session/created` 接管、后端特定的前缀读取、write-behind 缓冲区、序列化的 flush 链、HMR(热模块替换)种子注入与 dispose(资源释放)排空。纯粹的种子前缀碰撞检查与可序列化守卫已迁入 seam 包;剩余的编排仍然对正确性要求很高,且同样的修复被应用了两次。代码级 diff 表明两个后端在**全部**这些逻辑上要么字节相同、要么算法相同:四个 map(`states`/`buffers`/`chains`/`inits`)、`installWritePath`、`initFor`、`onCreated` 的四种分支、`flush`、`drain`、`serialize`、`adopt`、`adoptLivePrefix`、`assertVersion`,以及 `create`/`append`/`load` 的骨架。唯一的差异在于存储原语(写字节 vs. INSERT 行)。 +`dsh-session-persistence-jsonl` 与 `dsh-session-persistence-sqlite` 有意在不同存储介质上证明同一份 `SessionPersistence` 契约,但它们的写入路径编排是重复的:per-session 状态、`session/created` 接管、后端特定的前缀读取、write-behind 缓冲区、序列化的 flush 链、HMR(热模块替换)种子注入与 dispose(资源释放)排空。纯粹的种子前缀碰撞检查与可序列化守卫已迁入 seam 包;剩余的编排仍然对正确性要求很高,且同样的修复被应用了两次。代码级 diff 表明两个后端在全部这些逻辑上要么字节相同、要么算法相同:四个 map(`states`/`buffers`/`chains`/`inits`)、`installWritePath`、`initFor`、`onCreated` 的四种分支、`flush`、`drain`、`serialize`、`adopt`、`adoptLivePrefix`、`assertVersion`,以及 `create`/`append`/`load` 的骨架。唯一的差异在于存储原语(写字节 vs. INSERT 行)。 ## 决策 @@ -19,16 +19,16 @@ Status: implemented 六个方法(五个必需 + 一个可选的生命周期钩子)——协调器与存储之间唯一的 seam: - `name`——后端标签,用于 dispose 失败时的 `AggregateError`。 -- `loadStored(id)`——按 id 读取已存储的前缀,扫描**任何**存储范围(JSONL 的每个 cwd bucket;SQLite 的 id 全局唯一)。用于恢复/加载,以及通过 `!== undefined` 进行创建碰撞探测。 -- `loadLive(id, cwd)`——读取**限定于 `cwd`** 的已存储前缀。**与 `loadStored` 有意区分**:HMR live-adoption 只能接管与存活会话处于**同一 cwd** 的持久化日志;同 id 但不同 cwd 的日志是碰撞而非恢复。合并二者会重新引入跨 cwd 接管 bug。SQLite 忽略 `cwd`。 -- `appendBatch(meta, events, isMaterialized)`——持久追加一个连续批次,在尚未物化时**原子地**惰性物化会话(物化写入与首批事件必须一起提交——崩溃不得留下一个已物化但为空的会话;这就是为什么没有单独的 `materialize` 钩子)。 +- `loadStored(id)`——按 id 读取已存储的前缀,扫描任何存储范围(JSONL 的每个 cwd bucket;SQLite 的 id 全局唯一)。用于恢复/加载,以及通过 `!== undefined` 进行创建碰撞探测。 +- `loadLive(id, cwd)`——读取限定于 `cwd` 的已存储前缀。**与 `loadStored` 有意区分**:HMR live-adoption 只能接管与存活会话处于同一 cwd 的持久化日志;同 id 但不同 cwd 的日志是碰撞而非恢复。合并二者会重新引入跨 cwd 接管 bug。SQLite 忽略 `cwd`。 +- `appendBatch(meta, events, isMaterialized)`——持久追加一个连续批次,在尚未物化时原子地惰性物化会话(物化写入与首批事件必须一起提交——崩溃不得留下一个已物化但为空的会话;这就是为什么没有单独的 `materialize` 钩子)。 - `commitRepair(meta, tornMarker, closers)`——使崩溃修复持久化:截断损坏的尾部(当且仅当 `tornMarker !== undefined`)并追加 `closers`。**不要求原子性**——JSONL 合理地分两步 fsync(先截断再追加),SQLite 在一个事务中完成 DELETE+INSERT。用于 `load`(截断 + 合成 closers)和 live-adoption(仅截断,`closers = []`)。 - `list()`——列出所有已存储的元数据。 -- `close?()`——可选的生命周期清理(SQLite 关闭 db 句柄;JSONL 省略),在 dispose effect 中于静默排空**之后**被 await,因此 close 失败不会掩盖排空错误。 +- `close?()`——可选的生命周期清理(SQLite 关闭 db 句柄;JSONL 省略),在 dispose effect 中于静默排空之后被 await,因此 close 失败不会掩盖排空错误。 ### 不透明的 torn marker -保持 seam 整洁的唯一设计选择:崩溃修复中「损坏尾部在哪里」的 token 对协调器是**不透明的**。协调器计算合成 closers(它拥有来自 `dsh-session` 的 `interruptedTurnClosers`),但它只测试 `tornMarker !== undefined` 并将值原样传回 `commitRepair`——从不检视其内容。每个后端选择自己的 marker 类型:JSONL 使用要截断到的字节偏移,SQLite 使用要从其开始删除的 seq(两者恰好都是 `number`)。JSONL 后端将其 `committedBytes < buffer.byteLength` 比较折叠**在钩子内部**,因此返回的 marker 已经是 `number | undefined`;如果不做这层折叠,协调器就必须了解字节长度。 +保持 seam 整洁的唯一设计选择:崩溃修复中「损坏尾部在哪里」的 token 对协调器是不透明的。协调器计算合成 closers(它拥有来自 `dsh-session` 的 `interruptedTurnClosers`),但它只测试 `tornMarker !== undefined` 并将值原样传回 `commitRepair`——从不检视其内容。每个后端选择自己的 marker 类型:JSONL 使用要截断到的字节偏移,SQLite 使用要从其开始删除的 seq(两者恰好都是 `number`)。JSONL 后端将其 `committedBytes < buffer.byteLength` 比较折叠在钩子内部,因此返回的 marker 已经是 `number | undefined`;如果不做这层折叠,协调器就必须了解字节长度。 ## 测试 diff --git a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.i18n.yaml index 9fc5b9299f..7d33e94f0a 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-branded-ids.md: f6d066857d8904ae5343f12310266663806a0ae2 -2026-06-20-branded-ids.zh.md: 80c158e598f3007416d31a89a6704a759798e44e +2026-06-20-branded-ids.md: aab47a1413451edb707ae797e5b99cda6e34efad +2026-06-20-branded-ids.zh.md: 1ccfda3282069510bcdbfbddf4546305fd0923a5 diff --git a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.md b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.md index f6d066857d..aab47a1413 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.md +++ b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.md @@ -1,9 +1,9 @@ # RFC: Branded IDs everywhere they belong -English | [中文](2026-06-20-branded-ids.zh.md) - Status: implemented +English | [中文](2026-06-20-branded-ids.zh.md) + ## Problem The harness already brands three identifiers — `CallId` (`packages/llm/llm/src/brand.ts`), `SessionId` (`packages/core/session/src/types.ts`), and `AgentId` (`packages/core/agent/src/types.ts`) — using the `Branded = string & { readonly [BRAND]: B }` machinery (owned by the type-only `@deepseek-ai/dsh-brand` package at `packages/util/brand/` — see its [README](../../../../packages/util/brand/README.md)) and a zero-cost cast factory per type. `dsh-brand` also states the governing policy: *"Branding is for ids that cross package boundaries and could plausibly be confused; not every string needs a brand."* That policy is right; the problem is that it is only half-applied. Two gaps let a structurally-identical-but-semantically-wrong string slip through the type checker today. diff --git a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.zh.md b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.zh.md index 80c158e598..1ccfda3282 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.zh.md @@ -1,16 +1,16 @@ -# RFC:在所有应有之处使用 branded ID - -[English](2026-06-20-branded-ids.md) | 中文 +# RFC: 在所有应有之处使用 branded ID Status: implemented +[English](2026-06-20-branded-ids.md) | 中文 + ## 问题 harness 已经为三个标识符做了 brand 处理:`CallId`(`packages/llm/llm/src/brand.ts`)、`SessionId`(`packages/core/session/src/types.ts`)和 `AgentId`(`packages/core/agent/src/types.ts`),使用 `Branded = string & { readonly [BRAND]: B }` 机制(由纯类型包(package) `@deepseek-ai/dsh-brand` 拥有,位于 `packages/util/brand/`,见其 [README](../../../../packages/util/brand/README.md)),并为每个类型提供零开销的 cast 工厂。`dsh-brand` 还声明了治理策略:*"Branding 用于跨包边界且可能被混淆的 id;不是每个 string 都需要 brand。"* 这条策略是正确的;问题在于它只落实了一半。两处缺口使得结构相同但语义错误的 string 今天仍能通过类型检查器。 **缺口 1:bash seam 中未 brand 的 ID。** `BashTask.id` 以及所有执行器/工具边界使用裸 `string`,尽管生成的值与默认 session id 具有相同的 `name-N` 形状。模型还通过 `task_id` 返回该值,因此混淆 task id 和 session id 既类型正确又可达。 -bash **owner token** 是相关的子情形:`BashExecRequest.owner?: string` 和 `BashExecSpec.owner: string | undefined`(`packages/bash/bash/src/types.ts`)被文档描述为刻意*不透明*的隔离键,但在所有实际调用方中,该值就是所属 agent(智能体)的 `session.header.id`(`callerToken = (exec) => exec.agent?.session.header.id`,位于 `packages/bash/tool-bash/src/index.ts`),即一个穿着 `string` 外衣的 `SessionId`。它被用于访问控制比较(`owner !== callerToken(exec)`),因此一个不匹配但类型正确的 string 在此处就是一个跨会话隔离 bug,而当前类型系统无法捕获。这正是 [unify-the-agent-id-and-the-session-id](../../proposed/simplification/2026-06-20-unify-agent-and-session-id.md) 提案所称的"bash owner-token alias hole"。 +bash **owner token** 是相关的子情形:`BashExecRequest.owner?: string` 和 `BashExecSpec.owner: string | undefined`(`packages/bash/bash/src/types.ts`)被文档描述为刻意*不透明*的隔离键,但在所有实际调用方中,该值就是所属 agent(智能体)的 `session.header.id`(`callerToken = (exec) => exec.agent?.session.header.id`,位于 `packages/bash/tool-bash/src/index.ts`),即一个穿着 `string` 外衣的 `SessionId`。它被用于访问控制比较(`owner !== callerToken(exec)`),因此一个不匹配但类型正确的 string 在此处就是一个跨会话隔离 bug,而当前类型系统无法捕获。这正是 [unify-the-agent-id-and-the-session-id](../../proposed/simplification/2026-06-20-unify-agent-and-session-id.md) 提案所称的以 `session.header.id` 作为 owner 的别名缺口("bash owner-token alias hole")。 **缺口 2:既有 brand 的侵蚀。** `CallId`、`SessionId` 和 `AgentId` 在注册表 map、公开查找参数、ACP 会话跟踪和持久化协调器中退化为裸 string。在查找边界丢弃 brand 会使其主要保护失效。 @@ -18,7 +18,7 @@ bash **owner token** 是相关的子情形:`BashExecRequest.owner?: string` 纯类型变更。Brand 是零开销 cast;运行时行为、序列化、比较和协议格式(wire format)均不变。工作分三部分,全部遵循既有的"不是每个 string 都需要"策略。 -- **为 bash task id 加 brand。** 在 `packages/bash/bash/src/types.ts`(拥有该 id 的包)中添加 `BashTaskId = Branded<'BashTaskId'>` 及其同名工厂,从 `@deepseek-ai/dsh-brand` 导入 `Branded`,方式与 `SessionId`/`AgentId` 完全一致。brand 原语位于无依赖的 `dsh-brand` 工具包中,正是为了让 `dsh-bash` 仅依赖它就能为自己的 id 加 brand,而无需引入 `dsh-llm`(或 `dsh-session`)来获取 `Branded`。将其贯穿 `BashTask.id`、`BashExecutor` seam 方法(`get`/`ownerOf`/`readOutput`/`kill`)、`dsh-bash-local` 中的生成点(在创建时对计数器输出做一次 brand),以及 `dsh-tool-bash` 的校验/访问面(`validateTaskId` 返回 `BashTaskId`;`task_id` 在模型 string 到达的工具边界处被 brand)。 +- **为 bash task id 加 brand。** 在 `packages/bash/bash/src/types.ts`(*拥有*该 id 的包)中添加 `BashTaskId = Branded<'BashTaskId'>` 及其同名工厂,从 `@deepseek-ai/dsh-brand` 导入 `Branded`,方式与 `SessionId`/`AgentId` 完全一致。brand 原语位于无依赖的 `dsh-brand` 工具包中,正是为了让 `dsh-bash` 仅依赖它就能为自己的 id 加 brand,而无需引入 `dsh-llm`(或 `dsh-session`)来获取 `Branded`。将其贯穿 `BashTask.id`、`BashExecutor` seam 方法(`get`/`ownerOf`/`readOutput`/`kill`)、`dsh-bash-local` 中的生成点(在创建时对计数器输出做一次 brand),以及 `dsh-tool-bash` 的校验/访问面(`validateTaskId` 返回 `BashTaskId`;`task_id` 在模型 string 到达的工具边界处被 brand)。 - **铸造独立的 `OwnerToken` brand。** 在 `packages/bash/bash/src/types.ts` 中添加 `OwnerToken = Branded<'OwnerToken'>`;将 `BashExecRequest.owner` / `BashExecSpec.owner` / `BashExecutor.ownerOf` 的类型标注为 `OwnerToken | undefined`。`dsh-tool-bash` 消费方在边界处将 agent 的 `session.header.id`(一个 `SessionId`)cast 为 `OwnerToken`——这是两套词汇唯一交汇的地方。bash seam 从不导入 `dsh-session`。(理由见下一节。) @@ -46,7 +46,7 @@ export function OwnerToken(id: string): OwnerToken { ### 为什么不把 `owner` 类型标注为 `SessionId`? -执行器将 ownership 视为不透明的,不应依赖 session 模型。独立的 `OwnerToken` 保留了这一边界,同时防止裸 string 或 task id 被当作 owner 传入。`dsh-tool-bash` 拥有访问策略,由它执行从 `SessionId` 到 `OwnerToken` 的唯一转换。 +执行器将 ownership 视为不透明的,不应依赖 session 模型。独立的 `OwnerToken` 保留了这一边界,同时防止裸 string 或 task id 被当作 owner 传入。`dsh-tool-bash` 拥有访问策略,由它执行来自 `SessionId` 的唯一转换。 ## 不在范围内 / 可能的扩展 @@ -65,5 +65,5 @@ export function OwnerToken(id: string): OwnerToken { ## 后果 - **两个接口面的机械性改动。** 传播 brand 涉及 bash seam(接口 + 实现 + 消费方)以及 ACP session-id 接口和持久化协调器。改动面广但严重度低:遗漏的位置是编译错误而非静默 bug。变更可观察地为纯类型变更——无快照或 e2e 行为差异。它与 [unify-the-agent-id-and-the-session-id](../../proposed/simplification/2026-06-20-unify-agent-and-session-id.md) 提案相邻(两者都触及 session-id / owner-token 边界);如果该提案落地,`OwnerToken` 出于上述解耦理由仍与统一后的 id 保持独立。 -- **Brand 不做校验。** Brand 是混淆防护,不是正确性证明:一个*错误的* session id 只要仍是合法的 string,就和以前一样能通过类型检查器。本 RFC 不关闭这个缺口(见"不在范围内")——它只阻止传入错误*类别*的 id 这种错误。 +- **Brand 不做校验。** Brand 是混淆防护,不是正确性证明:一个*错误的* session id 只要仍是合法的 string,就和以前一样能通过类型检查器。本 RFC 不关闭这个缺口(见"不在范围内")——它只阻止这类*类别*错误:传入错误*种类*的 id。 - **"在哪里停下"仍是判断题。** 为 `BashTaskId` 加 brand 但不为 `ToolName` 加,为 `OwnerToken` 加但不为 `ModelId` 加,是对哪些 string"可能被混淆"的品味判断。合理的评审者可能想要更多或更少;`brand.ts` 中的策略是裁决依据,本 RFC 倾向于面向模型或用于访问控制的 id。 diff --git a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml index d10d531a66..602102a219 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-extract-example-app-packages.md: 3a0a0f5d4b329afed72bd3c00bf880989e24fe54 -2026-06-20-extract-example-app-packages.zh.md: 8945f0c97727479c9e847711a96fc5d18118e09e +2026-06-20-extract-example-app-packages.md: b0dd1fe32b2389578d3f3bd3672435923eb1a5d1 +2026-06-20-extract-example-app-packages.zh.md: 9f47c98c9c54357a304490e3d4075fad6cea855a diff --git a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.md b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.md index 3a0a0f5d4b..b0dd1fe32b 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.md +++ b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.md @@ -1,9 +1,9 @@ # RFC: Extract example apps into packages -English | [中文](2026-06-20-extract-example-app-packages.zh.md) - Status: implemented +English | [中文](2026-06-20-extract-example-app-packages.zh.md) + ## Problem An example folder is supposed to be *thin* — the variable wiring of a demo, not the demo's machinery. Before this change it was thick. Each example carried a hand-rolled `start.ts` boot bootstrap, an infra preamble (`timer`, and — for the stdio demos — `logger` + `hmr`), nested includes of three shared YAML fragments (`base.yml` / `base-core.yml` / `acp-agent/acp-tail.yml`), and per-example `agent-loop`/persistence/system-prompt config. The actual app — the spine of services every agent needs — was spread across the leaf and those includes. diff --git a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md index 8945f0c977..9f47c98c9c 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md @@ -1,9 +1,9 @@ -# RFC:将示例应用提取为独立包 - -[English](2026-06-20-extract-example-app-packages.md) | 中文 +# RFC: 将示例应用提取为独立包 Status: implemented +[English](2026-06-20-extract-example-app-packages.md) | 中文 + ## 问题 示例目录本应是*精简的*——只包含演示的可变接线,而非演示的基础设施。在此次变更之前,它是臃肿的。每个示例都携带一份手写的 `start.ts` 启动引导、一段基础设施前导(`timer`,以及 stdio 演示所需的 `logger` + `hmr`(热模块替换))、三个共享 YAML 片段的嵌套引用(`base.yml` / `base-core.yml` / `acp-agent/acp-tail.yml`),还有各示例自身的 `agent-loop`/persistence/system-prompt 配置。真正的应用——每个 agent(智能体)都需要的服务主干——散落在叶子配置和那些 include 中。 diff --git a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml index 08ab9fc7f0..05549751eb 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-package-hierarchy.md: faf5815222b20699a32f1af489e625ba3e891230 -2026-06-20-package-hierarchy.zh.md: 118367f2655bffbd270f259df4ade37a70dcb2d7 +2026-06-20-package-hierarchy.md: a06e963d118d895cc55a0f5e378bbf12678f3491 +2026-06-20-package-hierarchy.zh.md: a136f15a4197645b06fa0a68564a9e0464af1cba diff --git a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.md b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.md index faf5815222..a06e963d11 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.md +++ b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.md @@ -1,9 +1,9 @@ # RFC: Reorganize packages into a modular hierarchy -English | [中文](2026-06-20-package-hierarchy.zh.md) - Status: implemented +English | [中文](2026-06-20-package-hierarchy.zh.md) + ## Problem `packages/` was flat: 18 packages all sat at `packages//`, so a package's location said nothing about whether it was core product API, a swappable capability seam, a provider adapter, a product integration, or example/test support. The package README carried a `FIXME(package-hierarchy)` and `scripts/publint-all.ts` a `TODO(package-inventory)` flagging exactly this. Core packages, provider integrations, capability seams, example UI support, and snapshot-only replay support all looked equally foundational. diff --git a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.zh.md b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.zh.md index 118367f265..a136f15a41 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.zh.md @@ -1,9 +1,9 @@ -# RFC:将包重组为模块化层级结构 - -[English](2026-06-20-package-hierarchy.md) | 中文 +# RFC: 将包重组为模块化层级结构 Status: implemented +[English](2026-06-20-package-hierarchy.md) | 中文 + ## 问题 `packages/` 原先是扁平的:18 个包(package)全部位于 `packages//`,从路径上完全看不出一个包属于核心产品 API、可替换的能力 seam、提供方适配器、产品集成,还是示例/测试支撑。包的 README 带着 `FIXME(package-hierarchy)`,`scripts/publint-all.ts` 带着 `TODO(package-inventory)`,标记的正是这个问题。核心包、提供方集成、能力 seam、示例 UI 支撑和仅用于快照的回放支撑看起来同样基础。 diff --git a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml index 4a0b9d6ebc..decd9cec05 100644 --- a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-21-mandatory-app-attribution-headers.md: 4fa773e089b3a4b682e42269a66d85aeaf5c18f6 -2026-06-21-mandatory-app-attribution-headers.zh.md: 42cc396b5719adb2a2d71e0e9cf0d3554c5533a5 +2026-06-21-mandatory-app-attribution-headers.md: 132c827b48693af85fde67cf9d2d71cc84e853c6 +2026-06-21-mandatory-app-attribution-headers.zh.md: 9bba6d912b0b9bb33174c1ebb51a84dfdb47af0f diff --git a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md index 4fa773e089..132c827b48 100644 --- a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md +++ b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md @@ -1,9 +1,9 @@ # RFC: Mandatory `User-Agent` attribution for provider requests -English | [中文](2026-06-21-mandatory-app-attribution-headers.zh.md) - Status: implemented +English | [中文](2026-06-21-mandatory-app-attribution-headers.zh.md) + ## Problem LLM provider requests should identify the product making them. That is useful for provider-side support, abuse investigation, compatibility debugging, and traffic analytics. Before this RFC the harness only partially did this: the hand-rolled DeepSeek adapter sent a hand-copied `User-Agent` constant (`packages/llm/llm-deepseek/src/adapter.ts`), while the pi-ai-backed twin sent no harness-owned headers at all (`packages/llm/llm-pi-ai/src/adapter.ts`). New adapters could therefore omit attribution silently, and a library-backed adapter could drift from the hand-rolled adapter even though [the twin-adapter RFC](2026-06-13-twin-llm-adapters.md) exists to keep the provider seam honest across both implementations. diff --git a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md index 42cc396b57..9bba6d912b 100644 --- a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md @@ -1,9 +1,9 @@ -# RFC:对提供方请求强制携带 `User-Agent` 归属标识 - -[English](2026-06-21-mandatory-app-attribution-headers.md) | 中文 +# RFC: 对提供方请求强制携带 `User-Agent` 归属标识 Status: implemented +[English](2026-06-21-mandatory-app-attribution-headers.md) | 中文 + ## 问题 LLM(大语言模型)提供方请求应当标识发出请求的产品。这对提供方侧的技术支持、滥用调查、兼容性调试和流量分析都有价值。在本 RFC 之前,harness 只做了部分工作:手写的 DeepSeek 适配器发送了一个手动复制的 `User-Agent` 常量(`packages/llm/llm-deepseek/src/adapter.ts`),而基于 pi-ai 的孪生适配器则完全不发送 harness 自有的头部(`packages/llm/llm-pi-ai/src/adapter.ts`)。因此新适配器可以悄无声息地省略归属标识,而基于库的适配器也可能与手写适配器产生偏差——尽管[孪生适配器 RFC](2026-06-13-twin-llm-adapters.md) 的存在正是为了让两种实现在提供方 seam 上保持诚实。 @@ -15,9 +15,9 @@ LLM(大语言模型)提供方请求应当标识发出请求的产品。这 - **OpenRouter 的机制是提供方特有的。** 其当前文档说明应用归属通过 `HTTP-Referer`(必需)、`X-OpenRouter-Title` 和 `X-OpenRouter-Categories` 来追踪;`X-Title` 仅为向后兼容而接受。其 API 参考称这些头部为可选,并说它们使应用在 OpenRouter 上可被发现。这是一份具体的 OpenRouter 契约,而非 IETF 或 OpenAI 兼容 API 标准。 - **在 agent 工具生态中,`HTTP-Referer` 是一种 OpenRouter 感知的约定,而非通用 agent 约定。** 它足够常见,以至于 OpenRouter SDK 和示例直接暴露它,面向 OpenRouter 的框架通常需要一种方式来透传它。但 ACP(Agent Client Protocol)等 agent 协议在自己的 initialize 消息中协商名称、版本和能力,而模型提供方请求仍需 HTTP 层面的身份标识。因此「在 agent 世界中被接受」意味着「被 OpenRouter 集成所识别」,而非「可跨 agent 运行时或提供方移植」。 - **编程 agent 在 `User-Agent` 中标识产品和版本。** 公开实现在环境细节和提供方特有的附加头部上各有不同,但产品身份是共同契约;不存在通用的精确格式。 -- **标准化的通用客户端身份头部是 `User-Agent`。** RFC 9110 第 10.1.5 节将 `User-Agent` 定义为用户代理软件身份,说明它用于互操作性报告和分析,并说用户代理*应当*在每个请求中发送它(除非被配置为不发送)。这是唯一直接对应「哪个产品在发出此 HTTP 请求」的标准头部。 +- **标准化的通用客户端身份头部是 `User-Agent`。** RFC 9110 第 10.1.5 节将 `User-Agent` 定义为用户代理软件身份,说明它用于互操作性报告和分析,并说用户代理应当在每个请求中发送它(除非被配置为不发送)。这是唯一直接对应「哪个产品在发出此 HTTP 请求」的标准头部。 - **`Referer` 是标准的,但 OpenRouter 的 `HTTP-Referer` 不是标准字段。** RFC 9110 第 10.1.3 节将 `Referer` 定义为获取目标 URI 的来源 URI,并用大量篇幅讨论隐私限制。OpenRouter 则要求 `HTTP-Referer`,将其用作应用 URL 标识符。该名称和含义是 OpenRouter 特有的,尽管它形似标准 `Referer` 头部的 CGI 环境变量形式。 -- **`From` 是标准的,但不适合作为强制默认值。** RFC 9110 第 10.1.2 节将 `From` 定义为负责用户代理的人的电子邮件地址。机器人代理*应当*发送它以便服务器联系运营者,但非机器人代理出于隐私和安全策略考虑不应在未经用户显式配置的情况下发送。harness 可以后续支持运营者联系方式,但不得凭空捏造或全局强制要求。 +- **`From` 是标准的,但不适合作为强制默认值。** RFC 9110 第 10.1.2 节将 `From` 定义为负责用户代理的人的电子邮件地址。机器人代理应当发送它以便服务器联系运营者,但非机器人代理出于隐私和安全策略考虑不应在未经用户显式配置的情况下发送。harness 可以后续支持运营者联系方式,但不得凭空捏造或全局强制要求。 - **请求体中的 `user` 或 `metadata` 字段不是应用归属。** 部分模型 API 暴露稳定的终端用户标识符、请求元数据、标签或项目/账户头部。这些对滥用监控、内部计费、仪表盘或链路追踪有用,但它们要么标识的是终端用户而非产品,要么是提供方特有的 body schema,要么不保证能通过 OpenAI 兼容网关透传。它们不能替代静态的应用身份头部。 - **SDK 遥测头部标识的是 SDK,而非应用。** 官方和第三方 SDK 常发送库/版本头部。这些帮助 SDK 维护者调试其客户端,但除非应用显式提供产品归属层,否则它们不能标识 harness 作为应用。 - **pi-ai 有一流的头部钩子。** `@earendil-works/pi-ai` 的 `StreamOptions.headers` 将调用方头部最后合并(覆盖提供方默认值),因此基于库的适配器无需包装或上游改动即可满足与手写适配器相同的协议格式契约。mock 服务器测试套件对两个适配器都断言头部到达了线路。 diff --git a/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml index 7a19846a47..b164c4c0f7 100644 --- a/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-24-web-capability-seam.md: 3d0cdd89bb8366749ee0b3959244db1c57c0ccaa -2026-06-24-web-capability-seam.zh.md: 1cb1169f99b6eed22bcca650e0b3fe184f331307 +2026-06-24-web-capability-seam.md: fdb611be9efbf29717e41ffa2db86c55258ebe2e +2026-06-24-web-capability-seam.zh.md: f5db538f0565c4fc5667dcbec0791579246d238d diff --git a/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.md b/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.md index 3d0cdd89bb..fdb611be9e 100644 --- a/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.md +++ b/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.md @@ -1,9 +1,9 @@ # RFC: Web capability seam - stable tools over multiple providers -English | [中文](2026-06-24-web-capability-seam.zh.md) - Status: implemented +English | [中文](2026-06-24-web-capability-seam.zh.md) + ## Problem The harness needs model-facing web tools without binding the model contract to one vendor's API shape. Search is the immediate pressure point: supporting both Exa search and Perplexity search from the start — two deliberately different provider shapes (Exa returns a flat `results[]` of `{title, url, highlights, publishedDate}`; Perplexity returns a generated answer plus citations) — is what proves the normalized seam does not just mirror one vendor. Fetch is a separate capability: an anonymous public HTTP(S) fetch backend has transport, security, redirect, decoding, and size-limit concerns that are not the same as provider-backed search. diff --git a/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.zh.md b/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.zh.md index 1cb1169f99..f5db538f05 100644 --- a/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.zh.md @@ -1,4 +1,4 @@ -# RFC:Web 能力 seam——稳定的工具覆盖多个提供方 +# RFC: Web 能力 seam——稳定的工具覆盖多个提供方 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml index 06f5fb57d8..609b27aa6a 100644 --- a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-26-file-context-as-event-gate.md: 6e78e2df5f7969b5ed9b74c0b597e2fcacbe8e82 -2026-06-26-file-context-as-event-gate.zh.md: d69ccdbcea4b14dbd0291cf69af0bf7d5f3fadfc +2026-06-26-file-context-as-event-gate.md: ac9a8bcbc5bfda2b35cae4993497273608abf35b +2026-06-26-file-context-as-event-gate.zh.md: eda637f9adf8346779c70d59575863bf7e1162c9 diff --git a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.md b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.md index 6e78e2df5f..ac9a8bcbc5 100644 --- a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.md +++ b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.md @@ -1,9 +1,9 @@ # RFC: Make `dsh-fs-policy` an event-gate plugin, not a method interface -English | [中文](2026-06-26-file-context-as-event-gate.zh.md) - Status: implemented +English | [中文](2026-06-26-file-context-as-event-gate.zh.md) + ## Problem [The split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md) put `ctx.fileContext` between the model-facing tools and the `ctx.fs` provider: `dsh-tool-fs` injects `fileContext` and routes every `read`/`write`/`edit` through its methods. That makes `fileContext` **in-path and mandatory**. The tool cannot reach `ctx.fs` without it, the policy layer owns the fs I/O and the read windowing, and a deployment that does not want observed-state policy cannot simply drop the package — `dsh-tool-fs` would fail to resolve `ctx.fileContext`. diff --git a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md index d69ccdbcea..eda637f9ad 100644 --- a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md @@ -1,4 +1,4 @@ -# RFC:将 `dsh-fs-policy` 改为事件门控插件,而非方法接口 +# RFC: 将 `dsh-fs-policy` 改为事件门控插件,而非方法接口 Status: implemented @@ -72,7 +72,7 @@ editText(target: FsTarget, edit: FsEditRequest, expected?: { version: FsVersion **两个 `fs/*` 决策事件是单槽、先到先得的 waterfall。** `dsh-fs-policy` 不调用 `next()` 直接返回,因此在默认部署中它占据该槽位;更早注册或使用 `prepend` 的监听器会替代该策略。权限、审计和沙箱关注点仍留在可组合的 `tools/execute` waterfall 上。 -actor 在 `dsh-fs` 中类型为 `object`——一个纯粹的不透明载体,提供方 seam 从不读取或收窄它。owner 的推导(`actor.agent?.session`)和 `{ agent?: { session? } }` 结构形状完全留在 `dsh-fs-policy` 内部,由其在监听器中将 `object` actor 收窄为该形状。`dsh-fs` 拥有事件名和 fs 词汇;它**不**拥有策略层的运行时 owner 结构。 +actor 在 `dsh-fs` 中类型为 `object`——一个纯粹的不透明载体,提供方 seam 从不读取或收窄它。owner 的推导(`actor.agent?.session`)和 `{ agent?: { session? } }` 结构形状完全留在 `dsh-fs-policy` 内部,由其在监听器中将 `object` actor 收窄为该形状。`dsh-fs` 拥有事件名和 fs 词汇;它不拥有策略层的运行时 owner 结构。 ```ts import type { FsTarget, FsVersion, FsWriteIntent } from '@deepseek-ai/dsh-fs' @@ -154,7 +154,7 @@ interface Events { ## 验证 -测试固定了两条路径:无 `dsh-fs-policy` 时,根工具插件对 `dsh-fs-local` 启动,read、create、overwrite 和未读 edit 均成功;有策略时,未读 edit 返回 `FS_NOT_OBSERVED`,未读 overwrite 被 `createIfAbsent` 门控。策略决定后,后注册的 intent 监听器不会被触达。陈旧编辑通过提供方 CAS 失败,而策略不执行 `stat`;工具预算在两条路径上保持 read 一次 `stat`、write 或 edit 零次 `stat`。面向模型的 schema 逐字节不变,因此快照不变。 +测试固定了两条路径:无 `dsh-fs-policy` 时,根工具插件对 `dsh-fs-local` 启动,read、create、overwrite 和未读 edit 均成功;有策略时,未读 edit 返回 `FS_NOT_OBSERVED`,未读 overwrite 被 `createIfAbsent` 门控。策略决定后,后注册的 intent 监听器不会被触达。陈旧编辑通过提供方 CAS 失败,而策略不执行 `stat`;工具预算在两条路径上保持 read 一次 `stat`,write 或 edit 均为零次。面向模型的 schema 逐字节不变,因此快照不变。 ## 曾考虑的替代方案 diff --git a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml index 3bb8d3e607..d4d7cb2482 100644 --- a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-30-bash-stdin-env-trusted-plugin-surface.md: 72aae03361cbc088cf64f3548a43ac6253eb21eb -2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md: f661199048b7eaa359f792e96ac52baf8cd61fdf +2026-06-30-bash-stdin-env-trusted-plugin-surface.md: 712c17532bc1e6b95479aec5b544bc7e296952ec +2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md: db50f08dae30aa0c43e741a4f27f948f712954e0 diff --git a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md index 72aae03361..712c17532b 100644 --- a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md +++ b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md @@ -1,9 +1,9 @@ # RFC: stdin + extra env on the bash seam -English | [中文](2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md) - Status: implemented +English | [中文](2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md) + ## Problem The hooks subsystem runs external hook commands the way Claude Code and Codex do: a hook is a shell command that receives its event payload as **JSON on stdin** and reads context from a handful of **environment variables** (`CLAUDE_PROJECT_DIR`, `CLAUDE_PLUGIN_ROOT`, `PLUGIN_ROOT`, …). The harness already has a perfectly good command runner behind the `ctx.bash` capability seam ([dsh-bash](../../../../packages/bash/bash) → [dsh-bash-local](../../../../packages/bash/bash-local)), with process-group kills, output truncation/spill, and a credential scrub. Reusing it for hook execution means a hook bridge does not re-implement subprocess plumbing — but the seam had no way to write stdin or set extra env. This RFC adds those two inputs. diff --git a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md index f661199048..db50f08dae 100644 --- a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md @@ -1,4 +1,4 @@ -# RFC:在 bash seam 上支持 stdin 与额外 env +# RFC: 在 bash seam 上支持 stdin 与额外 env Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml index 2416919ab7..1b064ea80a 100644 --- a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-30-event-domain-semantics.md: e05c238c52052454d3e01e82767cddd9af316a9d -2026-06-30-event-domain-semantics.zh.md: 9048679ec7a7992852cce76bf43269f5499da792 +2026-06-30-event-domain-semantics.md: a9d33a7bfb549e1ec2102c23af78f91d9ae4b904 +2026-06-30-event-domain-semantics.zh.md: dc7390e3d2e1cda3469fa77389d0d6ad39b7a713 diff --git a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.md b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.md index e05c238c52..a9d33a7bfb 100644 --- a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.md +++ b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.md @@ -1,9 +1,9 @@ # RFC: Event-domain semantics — session is the fact log, agent is the live surface -English | [中文](2026-06-30-event-domain-semantics.zh.md) - Status: implemented +English | [中文](2026-06-30-event-domain-semantics.zh.md) + ## Problem The harness extends the agent loop through a Cordis event taxonomy (see [the microkernel event-taxonomy RFC](2026-06-11-microkernel-event-taxonomy.md)). As that taxonomy grew, the line between the three event domains blurred: diff --git a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.zh.md b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.zh.md index 9048679ec7..dc7390e3d2 100644 --- a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.zh.md @@ -1,4 +1,4 @@ -# RFC:事件域语义——session 是事实日志,agent 是运行时表面 +# RFC: 事件域语义——session 是事实日志,agent 是运行时表面 Status: implemented @@ -12,7 +12,7 @@ harness 通过 Cordis 事件分类体系扩展 agent loop(智能体循环) - `agent/*` 承载运行时实时信号,向插件传递 `Agent` 句柄。 - `tools/*` 承载工具注册表与执行 seam。 -两个问题促使我们固定语义。第一,若干轮次/步骤边界同时作为持久的 `SessionEvent`(`turn/start`、`turn/end`、`step/start`、`step/end`)**和**镜像的 `agent/*` emit(`agent/turn-start`、`agent/turn-end`、`agent/step-start`、`agent/step-end`)存在。消费方对同一事实有两个真源,每次生命周期变更都必须同时更新两处。第二,即将到来的 Hooks 子系统需要**一个**连贯且有文档的订阅表面——插件作者(以及基于其上构建的 Claude Code / Codex 钩子桥接)必须在不阅读循环代码的情况下知道应该监听 session 事件还是 agent 事件,以及原因。 +两个问题促使我们固定语义。第一,若干轮次/步骤边界同时作为持久的 `SessionEvent`(`turn/start`、`turn/end`、`step/start`、`step/end`)和镜像的 `agent/*` emit(`agent/turn-start`、`agent/turn-end`、`agent/step-start`、`agent/step-end`)存在。消费方对同一事实有两个真源,每次生命周期变更都必须同时更新两处。第二,即将到来的 Hooks 子系统需要一个连贯且有文档的订阅表面——插件作者(以及基于其上构建的 Claude Code / Codex 钩子桥接)必须在不阅读循环代码的情况下知道应该监听 session 事件还是 agent 事件,以及原因。 这套词汇是拦截决策、持久的 `hook/*` 日志,以及 Claude Code 和 Codex 桥接的基础。 @@ -21,7 +21,7 @@ harness 通过 Cordis 事件分类体系扩展 agent loop(智能体循环) **三个域,各司其职,以一条边界规则统一。** - **`session/*`——持久的、可回放的事实日志。** 拥有 `SessionEventMap`;每条记录仅含 JSON(无活对象)。每次追加触发一次 `session/event` emit,加上 `session/flush` 并行持久性检查点。它同时也是实时 transcript(文本记录)源:想渲染或响应已发生事件的消费方在此订阅,因此实时渲染与 `session/load` 回放共享同一路径。 -- **`agent/*`——运行时实时表面。** 始终携带活的 `Agent`。两种形态:拦截 waterfall(瀑布式事件)(`agent/request`、`agent/step-result`、`agent/turn-continuation`)可变更或否决;瞬态 emit(`agent/status`、`agent/error`、`agent/created`/`agent/disposed`、`agent/queued`)在持有 `Agent` 的情况下通知。轮次和步骤**边界**不在此处——它们是持久的 session 事件,从 `session/event` 读取;token 流(`assistant/chunk`)和中途 steering(中途引导)(`steering/message`)同理。 +- **`agent/*`——运行时实时表面。** 始终携带活的 `Agent`。两种形态:拦截 waterfall(瀑布式事件)(`agent/request`、`agent/step-result`、`agent/turn-continuation`)可变更或否决;瞬态 emit(`agent/status`、`agent/error`、`agent/created`/`agent/disposed`、`agent/queued`)在持有 `Agent` 的情况下通知。轮次和步骤边界不在此处——它们是持久的 session 事件,从 `session/event` 读取;token 流(`assistant/chunk`)和中途 steering(中途引导)(`steering/message`)同理。 - **`tools/*`——工具注册表与执行 seam。** **边界规则:** 持久的、可回放的事实是 `SessionEvent`;实时拦截或瞬态/活对象信号是 `agent`/`tools` Cordis 事件。轮次或步骤边界是持久事实,因此存在于 session 日志中并从 `session/event` 源读取——不会被镜像为 `agent/*` emit。 @@ -31,7 +31,7 @@ harness 通过 Cordis 事件分类体系扩展 agent loop(智能体循环) ## 后果 - 循环不再 emit 任何边界镜像;`closeStep` 仅追加 `step/end`,`closeTurn` 仅追加 `turn/end`。`Session.append` 负责 post-commit observer 隔离,因此抛出异常的边界 observer 无法改变轮次结果或饿死后续消费方;接受或内部校验失败仍会在边界进入日志之前逃逸。 -- 之前通过已移除 emit 观察边界的测试,现在观察持久的 `turn/start`/`turn/end`/`step/start`/`step/end` session 事件——它们固定的行为(边界顺序、步骤计数)不变;只是读取的源移到了规范源。那些测试「抛出异常的 turn 边界 emit 监听器」的用例被删除,因为该代码路径不再存在(没有 emit 可供抛出)。按照 [AGENTS.md「测试记录行为,而非黄金真相」](../../../../AGENTS.md),行为与其测试一同迁移(或一同消亡)。 +- 之前通过已移除 emit 观察边界的测试,现在观察持久的 `turn/start`/`turn/end`/`step/start`/`step/end` session 事件——它们固定的行为(边界顺序、步骤计数)不变;只是读取的源移到了规范源。那些测试*抛出异常的 turn 边界 emit 监听器*的用例被删除,因为该代码路径不再存在(没有 emit 可供抛出)。按照 [AGENTS.md「测试记录行为,而非黄金真相」](../../../../AGENTS.md),行为与其测试一同迁移(或一同消亡)。 - 循环仅在 `append('step/start')` 返回后才标记步骤已打开(`stepOpen = true`)。内部分发校验在日志推入之前运行,可能在不打开步骤的情况下拒绝;post-commit `session/event` observer 的失败被隔离在 `Session.append` 内部。因此该标记精确表示已提交的、欠一个后续 `step/end` 的边界。 - 完整实现见[简化 RFC「停止将持久边界镜像为 agent 事件」](../simplification/2026-06-20-remove-agent-boundary-mirror-events.md):全部四个边界镜像被移除,所有消费方从 `session/event` 读取边界。`agent/steering`(不是边界镜像)不在该 RFC 范围内,由其后续 RFC [移除 `agent/steering` 镜像 emit](../simplification/2026-07-04-remove-agent-steering-mirror.md) 单独移除——它镜像的是持久的 `steering/message`。 - Cordis 事件目录(`docs/cordis-catalog/events.md`)重新生成以移除镜像事件。 diff --git a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml index 3cff8c7aca..1af8dd8fe3 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-02-fs-per-session-cwd.md: 00643955d918dff87241f4b240bb7e6774d21a0b -2026-07-02-fs-per-session-cwd.zh.md: 73176cde3747a2eb8c03aadbf3f419bf27173d70 +2026-07-02-fs-per-session-cwd.md: 2513294d6bc991ee39155bbf20869829cca1a188 +2026-07-02-fs-per-session-cwd.zh.md: 2c3957113642fe2bf7b3a4f2b6186246b32aff3f diff --git a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.md b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.md index 00643955d9..2513294d6b 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.md +++ b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.md @@ -1,9 +1,9 @@ # RFC: Resolve filesystem paths against the caller's session cwd -English | [中文](2026-07-02-fs-per-session-cwd.zh.md) - Status: implemented +English | [中文](2026-07-02-fs-per-session-cwd.zh.md) + ## Problem The ACP bridge gives every session its own workspace: `session/new` records the editor's project directory as `SessionHeader.cwd`, and `dsh-tool-bash` defaults each bash call's `workdir` to the calling agent's `session.header.cwd` (see [the per-session cwd RFC work in `packages/ui/acp`](../../../../packages/ui/acp) and `resolveWorkdir` in `dsh-tool-bash`). So a bash command in session A runs in A's project, and in session B runs in B's — one server process, N workspaces. diff --git a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md index 73176cde37..2c39571136 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md @@ -1,9 +1,9 @@ -# RFC:相对文件系统路径按调用方的会话 cwd 解析 - -[English](2026-07-02-fs-per-session-cwd.md) | 中文 +# RFC: 相对文件系统路径按调用方的会话 cwd 解析 Status: implemented +[English](2026-07-02-fs-per-session-cwd.md) | 中文 + ## 问题 ACP(Agent Client Protocol)桥接层为每个会话提供独立的工作区:`session/new` 将编辑器的项目目录记录为 `SessionHeader.cwd`,`dsh-tool-bash` 将每次 bash 调用的 `workdir` 默认设为调用方 agent(智能体)的 `session.header.cwd`(见 [`packages/ui/acp`](../../../../packages/ui/acp) 中的 per-session cwd RFC 工作与 `dsh-tool-bash` 中的 `resolveWorkdir`)。因此会话 A 中的 bash 命令在 A 的项目目录执行,会话 B 中的在 B 的项目目录执行——一个服务器进程,N 个工作区。 @@ -24,7 +24,7 @@ ACP(Agent Client Protocol)桥接层为每个会话提供独立的工作区 提供方 seam 不得依赖 `dsh-agent`/`dsh-session`——它是一个文本存储后端,沙箱或远程实现同样满足该接口,而这些实现没有「agent 会话」的概念。工具已经接收了 `ToolExecution`(`exec`),其中携带 agent,因此工具是将 `exec → cwd` 投影并向提供方传递一个纯字符串的正确位置。这遵循「包(package)边界处显式优于隐式」的约定:基准目录作为显式参数传入,提供方据此行动,而非让提供方越界去读取它不应知晓的会话。这也与 `dsh-tool-bash` 一一对应,使两个面向模型的文件操作接口以相同方式解析路径。 -默认值只存在于**一个**地方——提供方的 `config.cwd`。`sessionCwd` 在没有会话时返回 `undefined` 而非 `process.cwd()`,因此工具永远不会自行制造一个提供方本应自行选择的基准目录。 +默认值只存在于一个地方——提供方的 `config.cwd`。`sessionCwd` 在没有会话时返回 `undefined` 而非 `process.cwd()`,因此工具永远不会自行制造一个提供方本应自行选择的基准目录。 ## 后果 diff --git a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml index 0401c48e08..d05c13ff78 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-02-result-time-applied-hunk-diffs.md: 81ab8b9827ddaec39d63e2a3f8fbb864085a9ac9 -2026-07-02-result-time-applied-hunk-diffs.zh.md: 2914c4242c4246ede8588967ed36b3f6c725c607 +2026-07-02-result-time-applied-hunk-diffs.md: fd02951f21319be2933bf3ffaddeb96bc2a6819c +2026-07-02-result-time-applied-hunk-diffs.zh.md: 4ed9a29bb023343cab28b8114453d17408bc429a diff --git a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md index 81ab8b9827..fd02951f21 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md +++ b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md @@ -1,9 +1,9 @@ # RFC: Result-time applied-hunk diffs for file mutations -English | [中文](2026-07-02-result-time-applied-hunk-diffs.zh.md) - Status: implemented +English | [中文](2026-07-02-result-time-applied-hunk-diffs.zh.md) + ## Problem The [tagged render-intent union](2026-07-02-tool-render-intent-union.md) gave `dsh-tool-fs` write/edit a `card:'diff'` at CALL time, derived purely from the tool's args: write ⇒ `{oldText:null, newText:content}` (the whole new file), edit ⇒ `{oldText:old_string, newText:new_string}` (the bare replaced snippet). An editor renders that as an inline diff, but it is a **context-free** diff — the bare `old_string`→`new_string` with no surrounding lines, and a `replace_all` that touched five scattered sites still renders as one snippet pair. diff --git a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md index 2914c4242c..4ed9a29bb0 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md @@ -1,14 +1,14 @@ -# RFC:结果时刻的 applied-hunk diff 用于文件变更 - -[English](2026-07-02-result-time-applied-hunk-diffs.md) | 中文 +# RFC: 结果时刻的 applied-hunk diff 用于文件变更 Status: implemented +[English](2026-07-02-result-time-applied-hunk-diffs.md) | 中文 + ## 问题 [tagged render-intent union](2026-07-02-tool-render-intent-union.md) 为 `dsh-tool-fs` 的 write/edit 在调用时刻提供了 `card:'diff'`,纯粹从工具参数推导:write ⇒ `{oldText:null, newText:content}`(整个新文件),edit ⇒ `{oldText:old_string, newText:new_string}`(裸替换片段)。编辑器将其渲染为行内 diff,但这是一个**无上下文**的 diff:裸的 `old_string`→`new_string` 没有周围行,而一次触及五个分散位置的 `replace_all` 仍然渲染为一对片段。 -在对接 `claude-agent-acp` 自身的 ACP(Agent Client Protocol) bridge 时可以看到完整编辑器 diff 的样子:变更应用后,它发出第二个 `tool_call_update`,其 diff 是**带 ±3 行上下文的 applied hunk**(`replace_all` 的每个变更位置各一个 hunk),由工具的 `structuredPatch` 重建。这个结果时刻的 hunk 正是让 Zed 在文件中**原位**显示变更(而非浮动片段)的关键。我们的工具止步于调用时刻的片段;完成后的结果只携带纯文本 "updated successfully",没有 diff。 +在对接 `claude-agent-acp` 自身的 ACP(Agent Client Protocol) bridge 时可以看到完整编辑器 diff 的样子:变更应用后,它发出第二个 `tool_call_update`,其 diff 是**带 ±3 行上下文的 applied hunk**(`replace_all` 的每个变更位置各一个 hunk),由工具的 `structuredPatch` 重建。这个结果时刻的 hunk 正是让 Zed 在文件中*原位*显示变更(而非浮动片段)的关键。我们的工具止步于调用时刻的片段;完成后的结果只携带纯文本 "updated successfully",没有 diff。 障碍在于一个 seam 边界:`presentResult(args, result)` 是 **`args` + 面向模型的 `result`(`{content, isError}`)的纯函数**——它在实时流式输出和会话日志回放中都会运行,因此必须具备回放确定性且不能做 I/O。它看不到文件的前后内容,而 `FsEditOutcome`/`FsWriteOutcome` 只携带替换计数和版本号,没有文本。因此无法计算——甚至无法携带——applied hunk 给 presenter。 @@ -37,7 +37,7 @@ type ToolExecuteReturn = ContentBlock[] | { content: ContentBlock[]; meta?: unkn ### 3. Bridge 渲染 `diff` 结果卡片 -`ToolResultView` 新增 `DiffResultView { card:'diff'; title?; diffs: FileDiff[] }`;bridge 结果侧的 `switch (view.card)` 增加 `diff` 分支,发出 `{type:'diff'}` 的 `ToolCallContent` 块(与调用侧分支对称)。ACP 的 `tool_call_update.content` 在编辑器中**替换**调用时的内容,因此结果 diff **取代**调用时刻的片段(并防止面向模型的结果文本覆盖它)——两次更新序列(先调用片段,再结果 diff)与 `claude-agent-acp` 完全一致。 +`ToolResultView` 新增 `DiffResultView { card:'diff'; title?; diffs: FileDiff[] }`;bridge 结果侧的 `switch (view.card)` 增加 `diff` 分支,发出 `{type:'diff'}` 的 `ToolCallContent` 块(与调用侧分支对称)。ACP 的 `tool_call_update.content` 在编辑器中替换调用时的内容,因此结果 diff **取代**调用时刻的片段(并防止面向模型的结果文本覆盖它)——两次更新序列(先调用片段,再结果 diff)与 `claude-agent-acp` 完全一致。 ## 曾考虑的替代方案 diff --git a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml index 8c2f7faf6d..607ff343ce 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-02-tool-render-intent-union.md: 8256f09f9c297658627d0c3d9e99ee1c5424b254 -2026-07-02-tool-render-intent-union.zh.md: 35bd775545c9131a20da9e7f7424506e4554eb4b +2026-07-02-tool-render-intent-union.md: 6b828c32fb79f43c0f974f2c9f032e11430de5b4 +2026-07-02-tool-render-intent-union.zh.md: 8c44178ca3e8986579e7ed696aec2f900705e9ad diff --git a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md index 8256f09f9c..6b828c32fb 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md +++ b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md @@ -1,9 +1,9 @@ # RFC: Tagged render-intent union for tool-call presentation -English | [中文](2026-07-02-tool-render-intent-union.zh.md) - Status: implemented +English | [中文](2026-07-02-tool-render-intent-union.zh.md) + ## Problem A tool declares how its calls render in a UI (an editor's tool-call card) through two callbacks, `presentCall`/`presentResult` on `ToolDefinition`, returning `ToolCallPresentation` / `ToolResultPresentation` with an optional `ToolTerminal` sub-shape. These grew incrementally into a **bag of optional fields**: `title`, `kind`, `rawInput`, `content`, `locations`, `terminal` on the call; `title`, `content`, `terminal` on the result; `cwd`/`output`/`exitCode`/`signal` on `ToolTerminal`. The split of responsibility is muddy: diff --git a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md index 35bd775545..8c44178ca3 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md @@ -1,4 +1,4 @@ -# RFC:用于工具调用展示的带标签 render-intent 联合类型 +# RFC: 用于工具调用展示的带标签 render-intent 联合类型 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml index f589fd9ddf..b28a70da27 100644 --- a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-03-filesystem-directory-listing-seam.md: bb8d9c4deda18b320b85d548bbd5bcb32f1c1d72 -2026-07-03-filesystem-directory-listing-seam.zh.md: ccc5ca67f58537134da5c5484b3d527ba84fe8d3 +2026-07-03-filesystem-directory-listing-seam.md: 8920e54993eb1402bd310d6ce78fb9866de628c9 +2026-07-03-filesystem-directory-listing-seam.zh.md: 5ca9b195d4bf5c1450c60451dd469a19dd54166f diff --git a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.md b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.md index bb8d9c4ded..8920e54993 100644 --- a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.md +++ b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.md @@ -1,9 +1,9 @@ # RFC: Add direct directory listing to the filesystem seam -English | [中文](2026-07-03-filesystem-directory-listing-seam.zh.md) - Status: implemented +English | [中文](2026-07-03-filesystem-directory-listing-seam.zh.md) + ## Problem `@deepseek-ai/dsh-fs` is the provider seam for filesystem access, with local and future non-local backends behind the same `ctx.fs` contract. Before this change it could resolve paths, stat targets, read text, stream text, write text, and edit text. That was enough for model-facing file tools, but not for non-model-facing consumers that need to enumerate directories without importing `node:fs`. diff --git a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md index ccc5ca67f5..5ca9b195d4 100644 --- a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md @@ -1,9 +1,9 @@ -# RFC:为文件系统 seam 添加直接目录列举能力 - -[English](2026-07-03-filesystem-directory-listing-seam.md) | 中文 +# RFC: 为文件系统 seam 添加直接目录列举能力 Status: implemented +[English](2026-07-03-filesystem-directory-listing-seam.md) | 中文 + ## 问题 `@deepseek-ai/dsh-fs` 是文件系统访问的提供方 seam,本地后端与未来的非本地后端共享同一个 `ctx.fs` 契约。在本次变更之前,它能解析路径、stat 目标、读取文本、流式读取文本、写入文本和编辑文本。这对面向模型的文件工具已经足够,但对于需要枚举目录而又不想直接导入 `node:fs` 的非模型侧消费方来说还不够。 diff --git a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml index 5c821e12fa..1ea6573424 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-05-prompt-variables-and-tool-guidance-ownership.md: fce9d555c8843b99fdbfa7b652b46d0b88053935 -2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md: 93a639a2ddac33cb1ceac57101cb6185fe6034ad +2026-07-05-prompt-variables-and-tool-guidance-ownership.md: 1819a730b214270304a8feb103a7f26e9c8d6e6e +2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md: 4211241b1b24fd461f5341bf8d777007a7a36482 diff --git a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md index fce9d555c8..1819a730b2 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md +++ b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md @@ -1,9 +1,9 @@ # RFC: Prompt variables and tool-guidance ownership -English | [中文](2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md) - Status: implemented +English | [中文](2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md) + ## Problem The assembled system prompt had four defects, all of one family: facts the harness already knows were restated by hand somewhere else, and drifted. diff --git a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md index 93a639a2dd..4211241b1b 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md @@ -1,9 +1,9 @@ -# RFC:Prompt 变量与工具指导归属 - -[English](2026-07-05-prompt-variables-and-tool-guidance-ownership.md) | 中文 +# RFC: Prompt 变量与工具指导归属 Status: implemented +[English](2026-07-05-prompt-variables-and-tool-guidance-ownership.md) | 中文 + ## 问题 组装后的系统提示词存在四个缺陷,同属一类:harness 已知的事实在别处被手工重述,然后漂移。 @@ -32,7 +32,7 @@ Status: implemented ### Persona 作为 order-0 section -`dsh-system-prompt` 拥有 order 为 `-100` 的 `harness:identity` 和 order 为 `0` 的配置 `deployment:persona`,因此两者在循环被替换时仍然存活。prompt 渲染只有一条路径 `renderPrompt(assembly)`,`agent/pre-step` 因此测量的正是用于压缩(compaction)的确切 prompt。agent 作用域的 `deployment:persona` 遮蔽全局默认值,允许 subagent provider 在发布前安装 persona。约定的 order 区间为:identity `-100`、persona `0`、工具指导 `100–199`。 +`dsh-system-prompt` 拥有 order 为 `-100` 的 `harness:identity` 和 order 为 0 的配置 `deployment:persona`,因此两者在循环被替换时仍然存活。prompt 渲染只有一条路径 `renderPrompt(assembly)`,`agent/pre-step` 因此测量的正是用于压缩(compaction)的确切 prompt。agent 作用域的 `deployment:persona` 遮蔽全局默认值,允许 subagent provider 在发布前安装 persona。约定的 order 区间为:identity `-100`、persona `0`、工具指导 `100–199`。 ### 工具指导归属 @@ -66,7 +66,7 @@ Status: implemented ## 后果 - 组装后的 prompt 中每个事实现在恰好有一个归属方,leaf YAML 中手工维护的工具行文已消除:加载或卸载一个工具插件不再需要编辑任何部署的 persona。 -- `{{model}}` 在组装时反映 `AgentOptions.model`。如果一个插件在 `agent/request` waterfall 中切换模型,prompt 对该步骤的声明就会过时;如果一个插件在那里**提供**模型(options.model 未设置——循环文档中记载的回退路径),变量在渲染时无值,包含 `{{model}}` 的 persona 会在 waterfall 运行前失败。两者的补救方式相同,就是归属规则本身:拥有延迟绑定模型事实的插件在 `system-prompt/assemble` waterfall 上提前声明它(`assembly.variables['model'] = …`)——一个归属方,两处声明;一个循环测试端到端固定了 supply 路径。已接受。 +- `{{model}}` 在组装时反映 `AgentOptions.model`。如果一个插件在 `agent/request` waterfall 中切换模型,prompt 对该步骤的声明就会过时;如果一个插件在那里提供模型(options.model 未设置——循环文档中记载的回退路径),变量在渲染时无值,包含 `{{model}}` 的 persona 会在 waterfall 运行前失败。两者的补救方式相同,就是归属规则本身:拥有延迟绑定模型事实的插件在 `system-prompt/assemble` waterfall 上提前声明它(`assembly.variables['model'] = …`)——一个归属方,两处声明;一个循环测试端到端固定了 supply 路径。已接受。 - 当一个已绑定的 provider 不存在时(尚未激活、已卸载、HMR(热模块替换)重载中),subagent 工具不存在,该窗口内的模型请求中不会包含它。这是诚实的状态——替代方案是注册一个 description 或执行都不可信的工具。 -- 严格性意味着 persona 可能在渲染时导致轮次失败(例如在无 cwd 的会话上使用 `{{cwd}}`)。失败是受控的——该轮次以 `error` 结束,循环存活——且这是一个我们**希望**大声暴露的撰写错误。 +- 严格性意味着 persona 可能在渲染时导致轮次失败(例如在无 cwd 的会话上使用 `{{cwd}}`)。失败是受控的——该轮次以 `error` 结束,循环存活——且这是一个我们希望大声暴露的撰写错误。 - 目前没有在 prompt 行文中转义字面 `{{name}}` 的语法;如果真实 prompt 确实需要,再行添加。 diff --git a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml index 2ef938def7..11d51bfef5 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-05-reconstructable-requests.md: 0978cd8760c6a0420be1bf0a3baf6b50c1a04a13 -2026-07-05-reconstructable-requests.zh.md: a4864c9e795ccc0da2cbbf0ca4d17a90c029858c +2026-07-05-reconstructable-requests.md: b07dbceaf6f3ecad64a464df6b97ee2a32284768 +2026-07-05-reconstructable-requests.zh.md: cb57d0915547b8a38b6afde7e36bec36c86e19c3 diff --git a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.md b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.md index 0978cd8760..b07dbceaf6 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.md +++ b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.md @@ -1,9 +1,9 @@ # RFC: Every LLM request is reconstructable from the session log -English | [中文](2026-07-05-reconstructable-requests.zh.md) - Status: implemented +English | [中文](2026-07-05-reconstructable-requests.zh.md) + ## Problem The request pipeline did not guarantee prefix stability for provider caching, and the session log could not reconstruct what the model saw. It omitted model, system prompt, and tool schemas while allowing per-call request rewrites. Cache behavior and replay equivalence therefore depended on whichever plugins happened to be loaded. diff --git a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.zh.md b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.zh.md index a4864c9e79..cb57d09155 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.zh.md @@ -1,4 +1,4 @@ -# RFC:每个 LLM(大语言模型)请求都可从会话日志重建 +# RFC: 每个 LLM(大语言模型)请求都可从会话日志重建 Status: implemented @@ -46,7 +46,7 @@ Status: implemented ## 后果 - 一个日志无法解释的请求不可能被意外构造——无论是循环还是监听器;变异已构建的请求会抛异常;每个 header 变更都是持久的、可 diff 的日志事件。 -- 在建议性通道之间做选择是变更频率的决策,而本设计使稳定的那个在结构上成为默认:`agent/session-prefix` 的贡献在每个循环实例中只组合一次并逐字复用,因此以零边际成本扩展可缓存前缀,且**不可能**在会话中途击穿提供方缓存;会话中途变化的内容通过仅追加的历史通道流入——`agent.inject()`、`tools/post-execute` 决策的 `additionalContext`、prompt-submit 的 `additionalContext`——每条都是持久的 `context/message`,付出一次代价后即被前缀缓存,代价是在历史和日志中累积。将会话冻结的开场内容路由到前缀,将变更通知路由到历史通道;逐步骤的仅限请求尾部槽位被有意放弃(无消费方,且持久追加覆盖了当前所有更新模式)。 +- 在建议性通道之间做选择是变更频率的决策,而本设计使稳定的那个在结构上成为默认:`agent/session-prefix` 的贡献在每个循环实例中只组合一次并逐字复用,因此以零边际成本扩展可缓存前缀,且不可能在会话中途击穿提供方缓存;会话中途变化的内容通过仅追加的历史通道流入——`agent.inject()`、`tools/post-execute` 决策的 `additionalContext`、prompt-submit 的 `additionalContext`——每条都是持久的 `context/message`,付出一次代价后即被前缀缓存,代价是在历史和日志中累积。将会话冻结的开场内容路由到前缀,将变更通知路由到历史通道;逐步骤的仅限请求尾部槽位被有意放弃(无消费方,且持久追加覆盖了当前所有更新模式)。 - 在提供方处仍需全价计算的内容是固有的且已记录的:压缩(其 `compact/*` 事件和 replace 节点)、真正的 prompt/工具变更(`request/header-delta`)、配置切换(同上)、带漂移的进程边界(`'resume'` 快照与前一快照不同)。提供方自身的 reasoning-content 排除由服务端管理。 - `step/start` 监听器行为变更(见上文)是对插件唯一可观察的语义变更;`agent/pre-step` 是当前请求的 seam。 - 工具结果裁剪(计划中)无需新机制:一个已记录的单节点 surface replace(`start === end`),携带同一 `callId` 下裁剪后的 `tool/result`——属压缩家族,回放正确,缓存击穿由相同的压力逻辑批量处理。 diff --git a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml index 74fbfda121..1de1e4c13d 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-05-subagent-provider-lifecycle-events.md: 6d711f2a6d8496a8a229ec63d86dd89816efb6f8 -2026-07-05-subagent-provider-lifecycle-events.zh.md: f412b031644c14ca70caae3efc72eefa9ce2c2ac +2026-07-05-subagent-provider-lifecycle-events.md: b5300706ce4c53a6d348a86803d221a4dcca9632 +2026-07-05-subagent-provider-lifecycle-events.zh.md: 8694612e5e3d4d65117896e337c170f47b31abb0 diff --git a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.md b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.md index 6d711f2a6d..b5300706ce 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.md +++ b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.md @@ -1,9 +1,9 @@ # RFC: Subagent provider-lifecycle events — `subagent/provider-added` / `subagent/provider-removed` -English | [中文](2026-07-05-subagent-provider-lifecycle-events.zh.md) - Status: implemented +English | [中文](2026-07-05-subagent-provider-lifecycle-events.zh.md) + ## Problem [The prompt-variables RFC](2026-07-05-prompt-variables-and-tool-guidance-ownership.md) makes `dsh-tool-subagent` DERIVE its model-facing wording from its provider: `SubagentProvider.inheritsParentContext` (spawn/ACP `false`, fork `true`) drives both the tool description and the `prompt` parameter description (`providerWording`), so the fork tool stops lying about context inheritance. That fix created a cross-fiber data dependency: a tool's description is fixed at TOOL REGISTRATION (deliberately — the description is where tool-choice guidance lives), but the provider arrives on its own plugin fiber, on no particular schedule. diff --git a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md index f412b03164..8694612e5e 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md @@ -1,12 +1,12 @@ -# RFC:Subagent 提供方生命周期事件——`subagent/provider-added` / `subagent/provider-removed` - -[English](2026-07-05-subagent-provider-lifecycle-events.md) | 中文 +# RFC: Subagent 提供方生命周期事件——`subagent/provider-added` / `subagent/provider-removed` Status: implemented +[English](2026-07-05-subagent-provider-lifecycle-events.md) | 中文 + ## 问题 -[prompt-variables RFC](2026-07-05-prompt-variables-and-tool-guidance-ownership.md) 让 `dsh-tool-subagent` 从其提供方**派生**面向模型的措辞:`SubagentProvider.inheritsParentContext`(spawn/ACP 为 `false`,fork 为 `true`)同时驱动工具描述和 `prompt` 参数描述(`providerWording`),使 fork 工具不再在上下文继承问题上对模型撒谎。这一修复引入了跨 fiber 的数据依赖:工具描述在**工具注册时**固定(这是有意为之——描述是 tool-choice 引导所在之处),但提供方在自己的插件 fiber 上到达,时机不确定。 +[prompt-variables RFC](2026-07-05-prompt-variables-and-tool-guidance-ownership.md) 让 `dsh-tool-subagent` 从其提供方派生面向模型的措辞:`SubagentProvider.inheritsParentContext`(spawn/ACP 为 `false`,fork 为 `true`)同时驱动工具描述和 `prompt` 参数描述(`providerWording`),使 fork 工具不再在上下文继承问题上对模型撒谎。这一修复引入了跨 fiber 的数据依赖:工具描述在工具注册时固定(这是有意为之——描述是 tool-choice 引导所在之处),但提供方在自己的插件 fiber 上到达,时机不确定。 如果在工具插件的 `apply` 时刻解析提供方,就会产生一个隐式的加载顺序要求("在 cordis.yml 中把后端列在工具前面")。这个要求不成立,因为 Cordis Loader 并发启动同级条目,且 `Entry.init()` 不会等待激活完成:延迟到达的后端即使列在前面,也可能让工具 fiber 失败。Loader 不提供同级顺序保证——"异步状态不是同步状态"(见[防御性模式](../../../defensive-patterns.md))。 @@ -17,15 +17,15 @@ Status: implemented - **`subagent/provider-added(provider)`**:一个提供方在 `ctx.subagents` 注册表中变为可解析。在注册时发出。 - **`subagent/provider-removed(name)`**:一个提供方离开注册表(其插件 fiber 被 dispose(资源释放)——卸载或 HMR(热模块替换)重载)。从注册的 disposer 中发出。 -`dsh-tool-subagent` 镜像其命名提供方的生命周期:当提供方可用(或变为可用)时注册工具——在那一刻从该提供方派生措辞——当提供方离开时注销工具,并在重新注册时(HMR 重载)重新派生。提供方不在时工具不存在,因此不会对模型撒谎。这里有意**不留下**任何需要文档化的加载顺序要求:事件让顺序问题消失,而非将其钉死。 +`dsh-tool-subagent` 镜像其命名提供方的生命周期:当提供方可用(或变为可用)时注册工具——在那一刻从该提供方派生措辞——当提供方离开时注销工具,并在重新注册时(HMR 重载)重新派生。提供方不在时工具不存在,因此不会对模型撒谎。这里有意不留下任何需要文档化的加载顺序要求:事件让顺序问题消失,而非将其钉死。 这些事件还完善了 seam 的词汇:`ctx.subagents` 是一个命名注册表,多个委派后端(`spawn`、`fork`、`acp`)在其上共存;一个其他插件从中派生状态的注册表,应当以类型化事件广播成员变化,而非要求轮询或依赖加载顺序。 ## 曾考虑的替代方案 - **在 `apply` 时解析提供方,不存在则抛异常**:否决。"先列后端"这一要求声称了 Loader 并不存在的顺序保证。 -- **重试查找(轮询直到提供方出现)**:最终能收敛,但在框架已有的机制(effect 注册 + disposal)之外发明了一套私有就绪协议;它也无法感知提供方**离开**,因此 HMR 会遗留一个措辞描述已 dispose 后端的工具。 -- **仅在 section 中放置 subagent 措辞,在组装时惰性解析**:同样能容忍任意加载顺序,但将 tool-choice 引导移出了**描述**,与 prompt-variables RFC 建立的所有权规则相矛盾(每个工具的语义和何时使用属于描述)。响应式注册既保持描述的权威性,又不依赖顺序。 +- **重试查找(轮询直到提供方出现)**:最终能收敛,但在框架已有的机制(effect 注册 + disposal)之外发明了一套私有就绪协议;它也无法感知提供方离开,因此 HMR 会遗留一个措辞描述已 dispose 后端的工具。 +- **仅在 section 中放置 subagent 措辞,在组装时惰性解析**:同样能容忍任意加载顺序,但将 tool-choice 引导移出了描述,与 prompt-variables RFC 建立的所有权规则相矛盾(每个工具的语义和何时使用属于描述)。响应式注册既保持描述的权威性,又不依赖顺序。 - **根据提供方名称而非提供方对象确定措辞**:`providerName` 本身是配置,重命名后的提供方会静默获得错误的措辞;从已解析提供方自身的 `inheritsParentContext` 派生则不会漂移。 ## 后果 @@ -33,4 +33,4 @@ Status: implemented - 从命名提供方派生状态的消费方响应 `subagent/provider-added`/`-removed` 事件,而非在 `apply` 时读取注册表;`dsh-tool-subagent` 是参考实现。 - **添加时大声失败;移除时按监听器隔离。** 添加监听器可以回滚注册。移除在 disposal 期间运行,因此单个监听器抛异常只会被记录日志,不会饿死后续镜像或干扰拆解流程。`start()` 仍在每次运行时按名称解析提供方,防止陈旧工具调用已移除的后端。见[事件目录](../../../cordis-catalog/events.md)与[生产者/消费者映射](../../../event-producer-consumer.md)。 - **工具不存在的窗口期。** 在后端 disposal 与重新注册之间(HMR 重载期间),模型看不到 subagent 工具。这是诚实的状态——替代方案是一个向空处分发的工具——工具注册表的 `tools/change` 事件发出会保持 prompt 组装的时效性。 -- **两个等待中的 fiber 共享同一 `toolName` 是无效配置,被延迟捕获。** 如果两个 `dsh-tool-subagent` 加载实例命名了不同的提供方但相同的 `toolName`,两者都会等待,先到达的提供方先注册;第二次注册仅在**其**提供方到达时才抛异常。插件中的 `TODO(subagent-dup-toolname)` 记录了这一影响范围;工具注册表的重名拒绝机制仍是最终防线。 +- **两个等待中的 fiber 共享同一 `toolName` 是无效配置,被延迟捕获。** 如果两个 `dsh-tool-subagent` 加载实例命名了不同的提供方但相同的 `toolName`,两者都会等待,先到达的提供方先注册;第二次注册仅在其提供方到达时才抛异常。插件中的 `TODO(subagent-dup-toolname)` 记录了这一影响范围;工具注册表的重名拒绝机制仍是最终防线。 diff --git a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml index a051d20478..57b6fca44e 100644 --- a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-06-timeout-deadline-library.md: 9906aa7cce40ffd7b5f7082199d05edb8d0a54b2 -2026-07-06-timeout-deadline-library.zh.md: dd1a60f9d7b91575b32e1cc85b3800cf823b6a6d +2026-07-06-timeout-deadline-library.md: e8a688fbd5285c5e177eca5339bb204e2e4b01bc +2026-07-06-timeout-deadline-library.zh.md: 427aa4e10fe90a69b8773ed739d92e37754a4998 diff --git a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.md b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.md index 9906aa7cce..e8a688fbd5 100644 --- a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.md +++ b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.md @@ -1,9 +1,9 @@ # RFC: A shared timeout/deadline primitive, with hard-kill left to each capability -English | [中文](2026-07-06-timeout-deadline-library.zh.md) - Status: implemented +English | [中文](2026-07-06-timeout-deadline-library.zh.md) + ## Problem Timeout handling was drifting apart across the tool-bearing capabilities, and the divergence was not superficial — it was the same logic re-implemented three ways, each with its own subtle correctness burden. diff --git a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md index dd1a60f9d7..427aa4e10f 100644 --- a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md @@ -1,4 +1,4 @@ -# RFC:共享的超时/截止时间原语,硬终止留给各能力自行实现 +# RFC: 共享的超时/截止时间原语,硬终止留给各能力自行实现 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml index 31025407be..1d65850a78 100644 --- a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-07-tool-call-timeout-policy.md: 0e69c8504dd34dfc4427bf1f3865a80be93eff9d -2026-07-07-tool-call-timeout-policy.zh.md: 2f4eca6eff9d135aad3fe538b887402a42ac6f84 +2026-07-07-tool-call-timeout-policy.md: 20e0b5d70166404e034c0d0ece75cec61cab0df9 +2026-07-07-tool-call-timeout-policy.zh.md: 00b85ce9e2e7ae4ba31a9770beefce9c2eb8c319 diff --git a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.md b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.md index 0e69c8504d..20e0b5d701 100644 --- a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.md +++ b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.md @@ -1,9 +1,9 @@ # RFC: Tool-call timeout policy as a plugin -English | [中文](2026-07-07-tool-call-timeout-policy.zh.md) - Status: implemented +English | [中文](2026-07-07-tool-call-timeout-policy.zh.md) + ## Problem The [timeout/deadline RFC](2026-07-06-timeout-deadline-library.md) extracted the timing-and-classification primitive into `@deepseek-ai/dsh-timeout`, but timeout policy was still attached to individual capabilities and model-facing schemas. `bash` exposed `timeoutMs`; `web_fetch` exposed `timeout_ms`; `web_search` had no model-facing timeout even though providers already honor `exec.signal`; a future grep/glob tool would either import the timeout library directly or invent its own timeout policy. That is the wrong authoring shape for a plugin SDK: a tool author should normally forward `exec.signal` to the implementation it calls, and deployment policy should decide the budget. diff --git a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md index 2f4eca6eff..00b85ce9e2 100644 --- a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md @@ -1,9 +1,9 @@ -# RFC:工具调用超时策略作为插件 - -[English](2026-07-07-tool-call-timeout-policy.md) | 中文 +# RFC: 工具调用超时策略作为插件 Status: implemented +[English](2026-07-07-tool-call-timeout-policy.md) | 中文 + ## 问题 [超时/截止时间 RFC](2026-07-06-timeout-deadline-library.md) 将计时与分类原语提取到了 `@deepseek-ai/dsh-timeout`,但超时策略仍然附着在各个能力和面向模型的 schema 上。`bash` 暴露了 `timeoutMs`;`web_fetch` 暴露了 `timeout_ms`;`web_search` 没有面向模型的超时参数,尽管提供方已经遵循 `exec.signal`;未来的 grep/glob 工具要么直接导入超时库,要么自行发明超时策略。对于一个插件 SDK 来说,这是错误的编写范式:工具作者通常只需将 `exec.signal` 转发给其调用的实现,而部署策略来决定预算。 @@ -36,7 +36,7 @@ ctx.tools.execute(exec) `@deepseek-ai/dsh-tools` 声明了一个 `tools/execute` waterfall,其基础 `next()` 是带规范化的分发 thunk——即同一个内部 `try`/`catch`,将抛出的工具错误(或未知工具错误)转换为 `isError` 的 `ToolExecutionResult`。监听器接收 `(exec, next)`:调用 `next()` 委托给分发(返回其结果,可选地包装),或返回替代结果以短路分发。整个流水线仍位于 `execute` 的外层 try/catch 内,因此抛出异常的监听器会变成 `isError` 结果,而非轮次失败。 -catch 是基础 `next()`(而非 waterfall 之外的东西)这一点至关重要:当提供方看到超时信号并抛出自己的上游中止错误时,注册表分发首先将其转换为普通错误结果,然后 `timeout-policy` 才能将最终结果替换为 `TOOL_TIMEOUT`。 +catch 是基础 `next`(而非 waterfall 之外的东西)这一点至关重要:当提供方看到超时信号并抛出自己的上游中止错误时,注册表分发首先将其转换为普通错误结果,然后 `timeout-policy` 才能将最终结果替换为 `TOOL_TIMEOUT`。 ### `timeout-policy` 插件 @@ -108,4 +108,4 @@ function toolTimeoutResult(timeoutMs: number): ToolExecutionResult { - 多个 `tools/execute` 监听器按普通 Cordis waterfall 顺序组合:调用 `next()` 的监听器包装下游监听器加分发;不调用 `next()` 直接返回的监听器短路它们。一个同时组合超时与未来重试/沙箱/指标包装器的部署通过注册顺序选择语义(「超时覆盖整个重试」vs「超时覆盖每次尝试」)。 - 按声明加入是一个有意的误配置风险:工具可以声明 `timeoutMs` 但不遵循 `exec.signal`,这样的工具在超时时不会停止。插件契约声明:声明预算意味着协作;web 工具在已转发信号的工具上验证了这一模式。 - 过渡期间 `bash` 和已迁移的 web 工具有意使用不同的超时路径:`TOOL_TIMEOUT` 是面向模型的工具调用预算,而 `BASH_TIMEOUT` 仍是 bash 和钩子使用的 bash 后端超时。 -- 与字面提案的偏差,按 implemented-RFC 规则记录:插件包为 `@deepseek-ai/dsh-timeout-policy`(而非 `tool-timeout`);信号替换是在 `next()` 之前就地修改 `exec.signal`(而非 `next({ ...exec, signal })`,Cordis 会忽略后者);逐工具预算声明在 `ToolDefinition` 上(`timeoutMs`,由拥有该工具的插件从其配置中设置),而非在本插件配置中按工具名映射——因此执行器是零配置的,拼错工具名不可能发生。以上三点均在上文「决策」一节中描述。 +- 与字面提案的偏差,按 implemented-RFC 规则记录:插件包为 `@deepseek-ai/dsh-timeout-policy`(而非 `tool-timeout`);信号替换是在 `next()` 之前就地修改 `exec.signal`(而非 `next({ ...exec, signal })`,Cordis 会忽略后者);逐工具预算声明在 `ToolDefinition` 上(`timeoutMs`,由拥有该工具的插件从其配置中设置),而非在本插件配置中按工具名映射——因此执行器是零配置的,拼错工具名不可能发生。以上三点均在上文 `## Decision` 中描述。 diff --git a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml index 3253751754..fda6a0406b 100644 --- a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-08-agent-scope-contexts.md: f238d58d90413d36e81b34c1a2c94e1291e889de -2026-07-08-agent-scope-contexts.zh.md: 0f4de12e782fc72d3761b6d46cd953ab4650654d +2026-07-08-agent-scope-contexts.md: b67d51f06f74f0460f76e9fc4b45699d00b7db46 +2026-07-08-agent-scope-contexts.zh.md: e37ea60418095cb34d354150aed79a937b1b3552 diff --git a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.md b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.md index f238d58d90..b67d51f06f 100644 --- a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.md +++ b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.md @@ -1,9 +1,9 @@ # RFC: The agent is a registration scope -English | [中文](2026-07-08-agent-scope-contexts.zh.md) - Status: implemented +English | [中文](2026-07-08-agent-scope-contexts.zh.md) + ## Problem One application needs to share infrastructure across many agents while letting each agent have its own tools, prompt contributions, policies, and listeners. Shared adapters, persistence, and user interfaces belong to the deployment; a persona, tool variant, or listener often belongs to one agent. diff --git a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md index 0f4de12e78..e37ea60418 100644 --- a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md @@ -1,4 +1,4 @@ -# RFC:agent 即注册作用域 +# RFC: agent 即注册作用域 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.i18n.yaml index 5f2ed7f3bc..c2a5189641 100644 --- a/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-12-agent-scope-runtime-design.md: 5fe44f2b0a79d91ce0e32a687ed183a5ffaef284 -2026-07-12-agent-scope-runtime-design.zh.md: 6e4f09e6780858c90b0cfbcf8709eca4c79ee414 +2026-07-12-agent-scope-runtime-design.md: 1940423db9364f56ab8a13e4d636f492f97f2d54 +2026-07-12-agent-scope-runtime-design.zh.md: bbfb06db7eb886f7bc34cdb8607729fb892cf5ba diff --git a/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md b/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md index 5fe44f2b0a..1940423db9 100644 --- a/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md +++ b/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md @@ -1,9 +1,9 @@ # RFC: Agent-scope runtime design and correctness -English | [中文](2026-07-12-agent-scope-runtime-design.zh.md) - Status: implemented +English | [中文](2026-07-12-agent-scope-runtime-design.zh.md) + ## Problem The [agent-scope contract](2026-07-08-agent-scope-contexts.md) is simple for contributors: register through `agent.ctx`, resolve one global-plus-agent view, publish only after setup, and retain the scope until work stops. The runtime must preserve that contract across a cooperative plugin framework, asynchronous creation, reentrant listeners, durable session commits, and worker or process failure. diff --git a/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md b/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md index 6e4f09e678..bbfb06db7e 100644 --- a/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md @@ -1,9 +1,9 @@ -# RFC:Agent 作用域运行时设计与正确性 - -[English](2026-07-12-agent-scope-runtime-design.md) | 中文 +# RFC: Agent 作用域运行时设计与正确性 Status: implemented +[English](2026-07-12-agent-scope-runtime-design.md) | 中文 + ## 问题 [agent 作用域契约](2026-07-08-agent-scope-contexts.md)对贡献者而言很简单:通过 `agent.ctx` 注册,解析出一个全局加单 agent 的视图,仅在 setup 完成后发布,并保持作用域直到工作停止。运行时必须在协作式插件框架、异步创建、可重入监听器、持久化会话提交以及 worker 或进程故障等场景下维护这份契约。 diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml index b0b2ec8727..f42c8c462e 100644 --- a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-14-acp-agent-client-protocol.md: 0bb2a2f2e307b8f23a3a9ca98edb2a2d3b5df0a8 -2026-06-14-acp-agent-client-protocol.zh.md: 7bb0e066572150c9c8fc0b94de1d5bf2d69527ee +2026-06-14-acp-agent-client-protocol.md: 50ad2620de1dada78c4a20101b631cc5b0e9f3d1 +2026-06-14-acp-agent-client-protocol.zh.md: c4b73c00083d63e5c024953cd8c9d8dbd94d6b0a diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.md b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.md index 0bb2a2f2e3..50ad2620de 100644 --- a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.md +++ b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.md @@ -1,9 +1,9 @@ # RFC: Agent Client Protocol (ACP) support — drive the coding agent from external editors -English | [中文](2026-06-14-acp-agent-client-protocol.zh.md) - Status: implemented +English | [中文](2026-06-14-acp-agent-client-protocol.zh.md) + ## Problem The harness originally exposed agents only through a readline loop. That surface could carry text, but it gave an editor no structured way to create or resume sessions, correlate prompt completion, stream reasoning and tool activity, render tool-specific UI, ask for permission, or cancel one conversation without disturbing another. ACP defines those interactions as JSON-RPC over stdio, and Zed is the target client used to make concrete compatibility decisions. diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md index 7bb0e06657..c4b73c0008 100644 --- a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md +++ b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md @@ -1,9 +1,9 @@ -# RFC:Agent Client Protocol(ACP)支持——从外部编辑器驱动编码 agent - -[English](2026-06-14-acp-agent-client-protocol.md) | 中文 +# RFC: Agent Client Protocol(ACP)支持——从外部编辑器驱动编码 agent Status: implemented +[English](2026-06-14-acp-agent-client-protocol.md) | 中文 + ## 问题 harness 最初仅通过 readline 循环暴露 agent。该接口能传输文本,但编辑器无法以结构化方式创建或恢复会话、关联 prompt 完成、流式输出推理(reasoning)与工具活动、渲染工具专属 UI、请求权限,或在不干扰其他对话的前提下取消某个对话。ACP(Agent Client Protocol)将这些交互定义为基于 stdio 的 JSON-RPC,Zed 是用于做出具体兼容性决策的目标客户端。 diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml index 825e4c2ed8..5a79faa4da 100644 --- a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-14-acp-multi-session.md: b96557d2d94711adb2183aa4f5dd8debf39c1de8 -2026-06-14-acp-multi-session.zh.md: 6a9f5e8162d46ed8719164247e22b8b9c5d26c61 +2026-06-14-acp-multi-session.md: a71f2d3d2daff3c8fae460e414d1f50facd5538f +2026-06-14-acp-multi-session.zh.md: 8b5ba46e949480d450f13aadad3ea82e0e048161 diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.md b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.md index b96557d2d9..a71f2d3d2d 100644 --- a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.md +++ b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.md @@ -1,9 +1,9 @@ # RFC: Multiplex concurrent ACP sessions over one connection -English | [中文](2026-06-14-acp-multi-session.zh.md) - Status: implemented +English | [中文](2026-06-14-acp-multi-session.zh.md) + ## Problem An ACP editor can keep several conversations alive over one agent subprocess. A single-active-session bridge would force extra processes and would not match Zed's client model, which tracks multiple session ids and concurrent loads. Multiplexing introduces isolation risks: events, prompt completion, cancellation, permission prompts, config selections, and predictable background-task ids must never cross session boundaries. diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.zh.md b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.zh.md index 6a9f5e8162..8b5ba46e94 100644 --- a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.zh.md +++ b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.zh.md @@ -1,9 +1,9 @@ -# RFC:在单个连接上多路复用并发 ACP 会话 - -[English](2026-06-14-acp-multi-session.md) | 中文 +# RFC: 在单个连接上多路复用并发 ACP 会话 Status: implemented +[English](2026-06-14-acp-multi-session.md) | 中文 + ## 问题 一个 ACP(Agent Client Protocol)编辑器可以在同一个 agent(智能体)子进程上保持多个对话。如果桥接层只支持单活跃会话,就不得不启动额外进程,也无法匹配 Zed 的客户端模型——该模型跟踪多个 session id 和并发加载。多路复用引入了隔离风险:事件、prompt 完成、取消、权限提示、配置选择以及可预测的后台 task id 绝不能跨越会话边界。 diff --git a/docs/rfc/implemented/feature/2026-06-15-code-mode.i18n.yaml b/docs/rfc/implemented/feature/2026-06-15-code-mode.i18n.yaml index 5aeee85382..6beb8d876f 100644 --- a/docs/rfc/implemented/feature/2026-06-15-code-mode.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-15-code-mode.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-15-code-mode.md: c64b6d6d8442e60240fa6c849833385ed50d71ff -2026-06-15-code-mode.zh.md: e9ae74f6629f3e34a0e97f0fa532764c70095bba +2026-06-15-code-mode.md: fb95f3010121fa432b3ac24e6aa477b1205a0ba7 +2026-06-15-code-mode.zh.md: 2da6628c1842bfd507c62d4b66a91f323e6fd0e7 diff --git a/docs/rfc/implemented/feature/2026-06-15-code-mode.md b/docs/rfc/implemented/feature/2026-06-15-code-mode.md index c64b6d6d84..fb95f30101 100644 --- a/docs/rfc/implemented/feature/2026-06-15-code-mode.md +++ b/docs/rfc/implemented/feature/2026-06-15-code-mode.md @@ -1,9 +1,9 @@ # RFC: Code Mode — the model writes TypeScript against the tool registry -English | [中文](2026-06-15-code-mode.zh.md) - Status: implemented +English | [中文](2026-06-15-code-mode.zh.md) + ## Problem In the registry's native presentation, the agent loop advertises every visible capability as a JSON-schema function definition. `ToolRegistry` contributes its schemas to the system-prompt assembly, the assembly's `tools` land on the wire (and in the logged request header), the model invokes one `tool-call` block per step, and the loop dispatches each call through `ctx.tools.execute()` **sequentially** (parallel tool execution is an explicit open TODO in `dsh-tools` and [docs/architecture.md](../../../architecture.md)), with **every** intermediate `tool-result` re-entering the model's context on the next request. diff --git a/docs/rfc/implemented/feature/2026-06-15-code-mode.zh.md b/docs/rfc/implemented/feature/2026-06-15-code-mode.zh.md index e9ae74f662..2da6628c18 100644 --- a/docs/rfc/implemented/feature/2026-06-15-code-mode.zh.md +++ b/docs/rfc/implemented/feature/2026-06-15-code-mode.zh.md @@ -1,9 +1,9 @@ -# RFC:Code Mode——模型针对工具注册表编写 TypeScript - -[English](2026-06-15-code-mode.md) | 中文 +# RFC: Code Mode——模型针对工具注册表编写 TypeScript Status: implemented +[English](2026-06-15-code-mode.md) | 中文 + ## 问题 在注册表的原生呈现方式下,agent loop(智能体循环)将每个可见能力以 JSON Schema 函数定义的形式通告给模型。`ToolRegistry` 将其 schema 贡献给系统提示词组装,组装结果中的 `tools` 落到协议格式(wire format)上(也记录在请求头日志中),模型每步调用一个 `tool-call` 块,循环通过 `ctx.tools.execute()` **逐个**分发每次调用(并行工具执行是 `dsh-tools` 和 [docs/architecture.md](../../../architecture.md) 中明确标注的 open TODO),且**每一个**中间 `tool-result` 都会在下一次请求时重新进入模型上下文。 @@ -20,7 +20,7 @@ Cloudflare 的 [Code Mode](https://blog.cloudflare.com/code-mode/) 提出了一 1. **Code Mode 是 `ToolRegistry`(`dsh-tools`)的一等呈现模式**,通过经校验的 `mode` 配置选择:`'native'`(默认,贡献可见能力 schema)、`'code'`(注册表仅贡献其保留的 `run_code` 传输通道加一份生成的 SDK `.d.ts` 到系统提示词中)或 `'both'`(原生 schema 加传输通道 + SDK)。注册表在源头塑造其权威贡献;协作式 prompt 组装的结果仍具权威性,记录在日志中的请求头精确反映该返回的呈现。 2. **代码执行是一个能力 seam**——`packages/code-runtime/` 包含接口包 `@deepseek-ai/dsh-code-runtime`,拥有 `ctx.codeRuntime`([能力 seam](../../implemented/architecture/2026-06-13-capability-seams.md);消费方 = `dsh-tools`,core 消费 seam 的先例见 `agent-loop` → `dsh-llm`)。运行时对工具一无所知:它接收一段程序和命名的异步绑定,执行程序,报告 `{ value, logs, error? }`。语言和基底是后端属性,因此未来的 Python 或容器后端只是另一个实现包,而非重新设计。 -3. **交付的实现是 `@deepseek-ai/dsh-code-runtime-worker`**:每次运行 spawn 一个全新的 Node worker 线程,对模型的 TypeScript 进行 type-strip 后执行,绑定通过 message port 桥接,环境为空,堆/输出/时间上限可配置,并支持硬终止。其信任姿态在设计上等同于 bash——无需 unsafe-acknowledgement flag——因为 harness 已经交付了 `dsh-bash-local`,后者以严格**更高**的环境权限执行模型编写的任意 shell 命令。 +3. **交付的实现是 `@deepseek-ai/dsh-code-runtime-worker`**:每次运行 spawn 一个全新的 Node worker 线程,对模型的 TypeScript 进行 type-strip 后执行,绑定通过 message port 桥接,环境为空,堆/输出/时间上限可配置,并支持硬终止。其信任姿态在设计上等同于 bash——无需 unsafe-acknowledgement flag——因为 harness 已经交付了 `dsh-bash-local`,后者以严格*更高*的环境权限执行模型编写的任意 shell 命令。 ### 注册表拥有模式 diff --git a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml index f5eae41ba4..b3ed1ae8ee 100644 --- a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-17-filesystem-tool-schemas.md: c2d3aa679599b1129a19b9082b9254ecf3103f12 -2026-06-17-filesystem-tool-schemas.zh.md: cd504a37d5ee25f6634b651d30099afe5acd6495 +2026-06-17-filesystem-tool-schemas.md: dba96157a0df548e4f153a0e233238af7400c087 +2026-06-17-filesystem-tool-schemas.zh.md: 3c135de9fa81fb333abc5fa6001a7ce7d7525a9d diff --git a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.md b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.md index c2d3aa6795..dba96157a0 100644 --- a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.md +++ b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.md @@ -1,9 +1,9 @@ # RFC: Filesystem tool schemas — model-facing read/write/edit shapes -English | [中文](2026-06-17-filesystem-tool-schemas.zh.md) - Status: implemented +English | [中文](2026-06-17-filesystem-tool-schemas.zh.md) + ## Problem [The filesystem capability-seam RFC](../architecture/2026-06-17-filesystem-capability-seam.md) defines the filesystem capability seam (`ctx.fs`), the package split (`dsh-fs`, `dsh-fs-local`, `dsh-tool-fs`, plus the `dsh-fs-policy` policy plugin), and the observed-file/stale-version policy for read-before-write/edit checks — which the [split-fs-seam](../simplification/2026-06-26-fsspec-style-fs-seam.md) and [event-gate](../architecture/2026-06-26-file-context-as-event-gate.md) RFCs moved off `ctx.fs` into the `dsh-fs-policy` plugin on the `fs/*` event gate. The remaining decision for the first filesystem tool delivery is the model-facing schema surface: what arguments the model sees for `read`, `write`, and `edit`. diff --git a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md index cd504a37d5..3c135de9fa 100644 --- a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md +++ b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md @@ -1,9 +1,9 @@ -# RFC:文件系统工具 schema——面向模型的读/写/编辑接口形状 - -[English](2026-06-17-filesystem-tool-schemas.md) | 中文 +# RFC: 文件系统工具 schema——面向模型的读/写/编辑接口形状 Status: implemented +[English](2026-06-17-filesystem-tool-schemas.md) | 中文 + ## 问题 [文件系统能力 seam RFC](../architecture/2026-06-17-filesystem-capability-seam.md) 定义了文件系统能力 seam(`ctx.fs`)、包(package)拆分(`dsh-fs`、`dsh-fs-local`、`dsh-tool-fs`,加上 `dsh-fs-policy` 策略插件),以及针对 read-before-write/edit 检查的 observed-file/stale-version 策略——[split-fs-seam](../simplification/2026-06-26-fsspec-style-fs-seam.md) 和 [event-gate](../architecture/2026-06-26-file-context-as-event-gate.md) RFC 后来将其从 `ctx.fs` 移至 `dsh-fs-policy` 插件的 `fs/*` 事件门上。首次文件系统工具交付剩余的决策是面向模型的 schema 接口:模型在 `read`、`write` 和 `edit` 中看到哪些参数。 @@ -51,7 +51,7 @@ schema 使用 snake_case 字段名(`file_path`、`old_string`、`new_string` 在默认 fs-policy 下,使用 `write` 更新已有文件需要同一执行上下文先前对该文件有过一次观测(read/write/edit);`dsh-fs-policy` 插件将观测到的版本作为 `fs/write-intent` 上的 stale guard 提供。创建新文件不需要先前观测。如果策略插件不存在,`write` 是无条件的裸提供方 create-or-overwrite。 -schema 不将 `expected_hash`、`expected_version` 或 `create_only` 作为面向模型的参数暴露。过期版本检查由后端产生的版本和策略插件的观测状态驱动,而非要求模型通过 schema 复制版本令牌。 +schema 不将 `expected_hash`、`expected_version` 或 `create_only` 作为面向模型的参数暴露。陈旧版本检查由后端产生的版本和策略插件的观测状态驱动,而非要求模型通过 schema 复制版本令牌。 ### `edit` @@ -66,7 +66,7 @@ schema 不将 `expected_hash`、`expected_version` 或 `create_only` 作为面 `edit` 要求同一执行上下文先前对该文件有过一次观测(任何窗口化的 read 都算——授权基于版本新鲜度,而非全文查看要求),或该上下文先前对该文件做过 write/edit。`dsh-fs-policy` 策略插件推导所有者并将记录的版本作为 stale guard 提供;提供方的 mutation lock 负责执行。 -首次实现拒绝 Codex 风格的 patch 语法和多模式 edit API。它使用一种严格的字面替换模式,使面向模型的契约保持简单,并让后端掌控精确匹配、重复匹配、行尾和过期版本的语义。 +首次实现拒绝 Codex 风格的 patch 语法和多模式 edit API。它使用一种严格的字面替换模式,使面向模型的契约保持简单,并让后端掌控精确匹配、重复匹配、行尾和陈旧版本的语义。 ## 结果形状 @@ -99,14 +99,14 @@ schema 测试固定每个工具的必填/可选参数集、空 `old_string` 拒 ## 曾考虑的替代方案 -- **Codex 风格的 patch 语法或多模式 edit API**:否决。一种严格的字面替换模式使面向模型的契约保持简单,并让后端掌控精确匹配、重复匹配、行尾和过期版本的语义。 +- **Codex 风格的 patch 语法或多模式 edit API**:否决。一种严格的字面替换模式使面向模型的契约保持简单,并让后端掌控精确匹配、重复匹配、行尾和陈旧版本的语义。 - **camelCase 参数名(OpenCode 风格)**:snake_case 与 Claude Code 及现有 harness 工具 schema 示例一致,且命名一旦发布即成为公开接口。 -- **面向模型的 `expected_hash` / `expected_version` / `create_only` 参数**:否决。过期检查由后端产生的版本和策略插件的观测状态驱动,从不依赖模型复制的脆弱令牌。 +- **面向模型的 `expected_hash` / `expected_version` / `create_only` 参数**:否决。陈旧检查由后端产生的版本和策略插件的观测状态驱动,从不依赖模型复制的脆弱令牌。 ## 后果 **首版 schema 有意小于 Claude Code 的。** 去掉 PDF pages、多模态 read、丰富的 grep/list flag 和 expected hash 字段使实现保持聚焦,但用户可能很快就会提出这些需求。它们将以独立 RFC 或聚焦的后续工作形式到来,而非对初始 schema 的重载。 -**v1 中没有显式的面向模型的 stale guard。** schema 不要求模型提供 expected hash/version。这是有意为之:过期检查来自后端产生的版本和 `dsh-fs-policy` 插件的观测状态,而非模型复制的脆弱令牌。文件系统安全失败通过 `dsh-fs` 拥有的结构化 `FsError` 代码浮现,而非模型提供的版本字段。 +**v1 中没有显式的面向模型的 stale guard。** schema 不要求模型提供 expected hash/version。这是有意为之:陈旧检查来自后端产生的版本和 `dsh-fs-policy` 插件的观测状态,而非模型复制的脆弱令牌。文件系统安全失败通过 `dsh-fs` 拥有的结构化 `FsError` 代码浮现,而非模型提供的版本字段。 **命名成为公开接口。** 一旦发布,将 `file_path` 改为 `filePath` 或 `old_string` 改为 `oldString` 会搅动提示词、示例和下游客户端。本 RFC 预先选择 snake_case,并将其视为稳定的面向模型的契约。 diff --git a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml index c8ce15293a..b25f0bf18b 100644 --- a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-18-acp-terminal-and-tool-rendering.md: cab89aa690c2068399ea5429a9c467410c744ce8 -2026-06-18-acp-terminal-and-tool-rendering.zh.md: 4047c493e63ac23f758de718616fd1f4bb29f7d4 +2026-06-18-acp-terminal-and-tool-rendering.md: 9bcb65a1e0b316d0b596a80816647d46ccfca782 +2026-06-18-acp-terminal-and-tool-rendering.zh.md: 3899e3ed21b386b1652736bc3de41d338efaa30e diff --git a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md index cab89aa690..9bcb65a1e0 100644 --- a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md +++ b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md @@ -1,9 +1,9 @@ # RFC: Rich ACP bash rendering — the terminal card via the `_meta` convention -English | [中文](2026-06-18-acp-terminal-and-tool-rendering.zh.md) - Status: implemented +English | [中文](2026-06-18-acp-terminal-and-tool-rendering.zh.md) + ## Problem The ACP bridge lets each tool own its call rendering via `presentCall`/`presentResult` (see [tool-call UI presentation](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md) and `packages/core/tools`). For `bash` we surface the exact command as the `tool_call` title, the model's `description` as a content text block, `kind: 'execute'`, and the completed output wrapped in a fenced ` ```console ` text block. diff --git a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md index 4047c493e6..3899e3ed21 100644 --- a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md +++ b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md @@ -1,9 +1,9 @@ -# RFC:富 ACP bash 渲染——通过 `_meta` 约定实现终端卡片 - -[English](2026-06-18-acp-terminal-and-tool-rendering.md) | 中文 +# RFC: 富 ACP bash 渲染——通过 `_meta` 约定实现终端卡片 Status: implemented +[English](2026-06-18-acp-terminal-and-tool-rendering.md) | 中文 + ## 问题 ACP(Agent Client Protocol)桥接层允许每个工具通过 `presentCall`/`presentResult` 自行控制调用渲染(见 [tool-call UI presentation](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md) 与 `packages/core/tools`)。对于 `bash`,我们将确切命令作为 `tool_call` 标题呈现,模型的 `description` 作为一个内容文本块,`kind: 'execute'`,完成后的输出包裹在 ` ```console ` 围栏文本块中。 @@ -27,7 +27,7 @@ Zed 侧(`crates/agent_servers/src/acp.rs`,已验证):收到 `ToolCall` 1. **能力声明。** `initialize` 读取 `clientCapabilities._meta.terminal_output`,桥接层按连接记住它。 2. **提供方无关的展示词汇。** `dsh-tools` 新增一种终端形态的展示结构,工具可返回它——提供方无关(`cwd`、输出 `data`、`exitCode`/`signal`),不含 ACP 类型。`dsh-tool-bash` 为 `bash` 返回该结构(cwd 来自解析后的工作目录;输出与退出从运行结果解析)。 -3. **桥接映射。** 当客户端声明了该能力时,桥接层将展示结构映射为:在 `tool_call` 上,`content:[…, {type:'terminal', terminalId}]`(工具的任何 `content`,如描述,渲染在终端块之前)+ `_meta.terminal_info.{terminal_id,cwd}`;在 `tool_call_update` 上,`_meta.terminal_output.{terminal_id,data}`(捕获的输出)+ `_meta.terminal_exit.{terminal_id, exit_code|signal}`(解析后的退出),且 update 的文本 `content` 被省略(ACP 的 `tool_call_update.content` 会**替换**调用的 content 集合,因此重新发送围栏块会覆盖终端内容块)。`terminalId` 由 harness 的 `callId` 派生(稳定、每次调用唯一)。当能力未声明时,桥接层在调用上发送描述内容块,在 update 上发送既有的 ` ```console ` 文本内容——行为不变。 +3. **桥接映射。** 当客户端声明了该能力时,桥接层将展示结构映射为:在 `tool_call` 上,`content:[…, {type:'terminal', terminalId}]`(工具的任何 `content`,如描述,渲染在终端块之前)+ `_meta.terminal_info.{terminal_id,cwd}`;在 `tool_call_update` 上,`_meta.terminal_output.{terminal_id,data}`(捕获的输出)+ `_meta.terminal_exit.{terminal_id, exit_code|signal}`(解析后的退出),且 update 的文本 `content` 被省略(ACP 的 `tool_call_update.content` 会替换调用的 content 集合,因此重新发送围栏块会覆盖终端内容块)。`terminalId` 由 harness 的 `callId` 派生(稳定、每次调用唯一)。当能力未声明时,桥接层在调用上发送描述内容块,在 update 上发送既有的 ` ```console ` 文本内容——行为不变。 4. **退出信息从渲染输出中解析;无新执行路径,无实时流式传输。** 输出在完成时附加(来自 agent 自身的 `tool/result`),不逐 token 流式传输。退出状态(`_meta.terminal_exit.{exit_code,signal}`)确实会发出:纯 `presentResult(args, result)` seam 只能看到内容块,因此 `dsh-tool-bash` 通过解析 `renderResult` 追加的状态标记(`[exit code: N]` / `[killed by signal: …]`)来恢复结构化退出信息——解析是标记发出的精确逆操作,二者在同一文件中共同演进,一个往返测试守护这对关系。资源释放不受影响:无需新增拆除逻辑,因为桥接层从未创建客户端侧终端。 ## 曾考虑的替代方案 diff --git a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml index aff86591fb..d99478bc53 100644 --- a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-18-compaction-capability-seam.md: 31b06905924a07a7f0c2af427d8868585966f1a7 -2026-06-18-compaction-capability-seam.zh.md: 1675484ed65e5cd890f420d4bdd1e16e2a95b2ef +2026-06-18-compaction-capability-seam.md: e88b3fd8267f65bba136398df9c439e371237912 +2026-06-18-compaction-capability-seam.zh.md: 75049079a2d85e27301e53b891228c1cbc87fac3 diff --git a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.md b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.md index 31b0690592..e88b3fd826 100644 --- a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.md +++ b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.md @@ -1,9 +1,9 @@ # RFC: Compaction as a capability seam (abstract contract + basic backend) -English | [中文](2026-06-18-compaction-capability-seam.zh.md) - Status: implemented +English | [中文](2026-06-18-compaction-capability-seam.zh.md) + ## Problem A long-running agent conversation grows without bound. As the event log accumulates turns, the derived message history eventually approaches the model's context window — the model then truncates mid-response (`max-tokens`) or degrades. **Compaction** is the mitigation: replace a run of older history with a concise summary, keeping recent context intact. diff --git a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.zh.md b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.zh.md index 1675484ed6..75049079a2 100644 --- a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.zh.md +++ b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.zh.md @@ -1,4 +1,4 @@ -# RFC:压缩作为能力 seam(抽象契约 + 基础后端) +# RFC: 压缩作为能力 seam(抽象契约 + 基础后端) Status: implemented @@ -66,7 +66,7 @@ request = waterfall agent/request ⟵ pure request transform (hooks, model s ### 近似收敛不变式 -`resolveConfig` 校验数值参数,但**不**基于虚构的摘要长度不变式来拒绝。收敛是动态的:提供方的输出上限可能被隐藏或显式的推理 token 消耗,模型可能生成不可预测大小的摘要。`maxTokens` 仅是摘要调用的提供方侧生成上限;推理块在检查点存储前被剥离。如果压缩后的 surface 仍超阈值,`compactIfNeeded()` 最多额外重压缩头部检查点 `compactionRetries` 次,但每次提交的摘要必须小于其遮蔽的内容。唯一的残余情况是上述单单元溢出(一个向后取整的超大步骤可能将保留尾部推过预算),这恰好是上述范围外的关注点,而非抖动 bug。 +`resolveConfig` 校验数值参数,但不基于虚构的摘要长度不变式来拒绝。收敛是动态的:提供方的输出上限可能被隐藏或显式的推理 token 消耗,模型可能生成不可预测大小的摘要。`maxTokens` 仅是摘要调用的提供方侧生成上限;推理块在检查点存储前被剥离。如果压缩后的 surface 仍超阈值,`compactIfNeeded()` 最多额外重压缩头部检查点 `compactionRetries` 次,但每次提交的摘要必须小于其遮蔽的内容。唯一的残余情况是上述单单元溢出(一个向后取整的超大步骤可能将保留尾部推过预算),这恰好是上述范围外的关注点,而非抖动 bug。 ### Surface 替换:`compact/*` 事件仅存在于日志;一条 `user/message` 承载摘要 diff --git a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml index 1da7113f51..20172e4369 100644 --- a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-21-subagent-capability-seam.md: 2bed84cd9166e8aa1ad5fa65b3afa44b8a842045 -2026-06-21-subagent-capability-seam.zh.md: a5917c14141dd06c14b4f45c5f6e4703f0eb661f +2026-06-21-subagent-capability-seam.md: ff8ca7d6292055715d94b3878860bffafb8a8057 +2026-06-21-subagent-capability-seam.zh.md: c11623531c753cd454621f450f33cff5edbbf815 diff --git a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.md b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.md index 2bed84cd91..ff8ca7d629 100644 --- a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.md +++ b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.md @@ -1,9 +1,9 @@ # RFC: Subagent capability seam -English | [中文](2026-06-21-subagent-capability-seam.zh.md) - Status: implemented +English | [中文](2026-06-21-subagent-capability-seam.zh.md) + > The full seam is shipped: the `dsh-subagent` interface, the `dsh-subagent-mock` test backend, and the `dsh-tool-subagent` consumer; the two in-process backends (`dsh-subagent-spawn`, `dsh-subagent-fork`); the nested-agent snapshot infrastructure ([per-session snapshot replay](../testing/2026-06-22-subagent-snapshot-replay.md)); and the out-of-process `dsh-subagent-acp` backend ([its RFC](2026-06-22-acp-subagent-backend.md)). ## Problem diff --git a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.zh.md b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.zh.md index a5917c1414..c11623531c 100644 --- a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.zh.md +++ b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.zh.md @@ -1,9 +1,9 @@ -# RFC:Subagent 能力 seam - -[English](2026-06-21-subagent-capability-seam.md) | 中文 +# RFC: Subagent 能力 seam Status: implemented +[English](2026-06-21-subagent-capability-seam.md) | 中文 + > 完整 seam 已交付:`dsh-subagent` 接口、`dsh-subagent-mock` 测试后端与 `dsh-tool-subagent` 消费方;两个进程内后端(`dsh-subagent-spawn`、`dsh-subagent-fork`);嵌套 agent 快照基础设施([逐会话快照回放](../testing/2026-06-22-subagent-snapshot-replay.md));以及进程外后端 `dsh-subagent-acp`([其 RFC](2026-06-22-acp-subagent-backend.md))。 ## 问题 @@ -43,7 +43,7 @@ bash seam([能力 seam](../../implemented/architecture/2026-06-13-capability-s ### 两类可选能力,两种发现方式 -- **启动时特性**(`outputSchema`、`depthLimit`、`toolFilter`、`persona`)挂在静态的 `provider.capabilities` 描述符上。服务在委派**之前**检查每个被请求的特性,如果提供方不支持则**大声拒绝**(`SubagentError('UNSUPPORTED_CAPABILITY')`),绝不接受后静默忽略。这些特性必须在 run 存在之前检查,因此不能是运行时方法。 +- **启动时特性**(`outputSchema`、`depthLimit`、`toolFilter`、`persona`)挂在静态的 `provider.capabilities` 描述符上。服务在委派之前检查每个被请求的特性,如果提供方不支持则**大声拒绝**(`SubagentError('UNSUPPORTED_CAPABILITY')`),绝不接受后静默忽略。这些特性必须在 run 存在之前检查,因此不能是运行时方法。 - **运行时特性**(通过 `sendMessage` 进行 steering、通过 `resume` 进行后续对话)是 `SubagentRun` 上的**可选方法**。方法的存在本身即为能力,TypeScript 类型收窄即为发现机制:消费方不经收窄就无法调用不存在的方法,因此不存在静默降级路径,也不需要额外的 flags 对象来保持同步。 ### Fork 与 fresh 是独立后端,而非一个 flag diff --git a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml index 2939af3939..99c3a2b5e9 100644 --- a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-22-acp-subagent-backend.md: 7eb03ddf68f54c29524944e7b8bc801eb1724fe6 -2026-06-22-acp-subagent-backend.zh.md: 249f5a5ebf18d42f3d83d2159f6c2bcb52a245c3 +2026-06-22-acp-subagent-backend.md: c02b027177ae96d75ff0d3dcac227145fe71b340 +2026-06-22-acp-subagent-backend.zh.md: 2b4db4e20fd872d21ffb72b1c2a4432c6f0103a9 diff --git a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.md b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.md index 7eb03ddf68..c02b027177 100644 --- a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.md +++ b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.md @@ -1,9 +1,9 @@ # RFC: ACP subagent backend (out-of-process delegation) -English | [中文](2026-06-22-acp-subagent-backend.zh.md) - Status: implemented +English | [中文](2026-06-22-acp-subagent-backend.zh.md) + ## Problem The subagent seam ([the seam RFC](2026-06-21-subagent-capability-seam.md)) was built so multiple backends coexist by name on `ctx.subagents`. The in-process backends (`-spawn`/`-fork`) run a child as a second `Agent` on the SAME cordis context — cheap, but the child shares the parent's process, model client, and tools. The seam's whole point was to also support an OUT-OF-PROCESS child reached over a protocol, proving the abstraction generalizes across a process boundary. This RFC adds the first such backend: an Agent Client Protocol (ACP) client. diff --git a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.zh.md b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.zh.md index 249f5a5ebf..2b4db4e20f 100644 --- a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.zh.md +++ b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.zh.md @@ -1,16 +1,16 @@ -# RFC:ACP subagent 后端(进程外委派) - -[English](2026-06-22-acp-subagent-backend.md) | 中文 +# RFC: ACP subagent 后端(进程外委派) Status: implemented +[English](2026-06-22-acp-subagent-backend.md) | 中文 + ## 问题 -subagent seam([seam RFC](2026-06-21-subagent-capability-seam.md))的设计使多个后端可以按名称共存于 `ctx.subagents`。进程内后端(`-spawn`/`-fork`)将子 agent(智能体)作为第二个 `Agent` 运行在**同一个** Cordis 上下文上:开销低,但子 agent 与父 agent 共享进程、模型客户端和工具。seam 的核心意义在于同时支持通过协议到达的**进程外**子 agent,以证明该抽象能跨越进程边界泛化。本 RFC 添加第一个此类后端:一个 ACP(Agent Client Protocol)客户端。 +subagent seam([seam RFC](2026-06-21-subagent-capability-seam.md))的设计使多个后端可以按名称共存于 `ctx.subagents`。进程内后端(`-spawn`/`-fork`)将子 agent(智能体)作为第二个 `Agent` 运行在同一个 Cordis 上下文上:开销低,但子 agent 与父 agent 共享进程、模型客户端和工具。seam 的核心意义在于同时支持通过协议到达的进程外子 agent,以证明该抽象能跨越进程边界泛化。本 RFC 添加第一个此类后端:一个 ACP(Agent Client Protocol)客户端。 ## 决策 -`@deepseek-ai/dsh-subagent-acp` 注册一个 `SubagentProvider`,将每个子 agent 运行在一个**派生的子进程**中,并以 ACP *客户端*身份驱动它。它是现有服务端桥接 `@deepseek-ai/dsh-acp`(ACP *agent*)的方向反转孪生体:桥接**应答** `initialize`/`newSession`/`prompt`;本后端**调用**它们并**实现** `Client` 回调(`sessionUpdate`、`requestPermission`)。将配置的 spawn 命令指向 `acp-agent` 示例,即可让 harness 与自身进程通信。 +`@deepseek-ai/dsh-subagent-acp` 注册一个 `SubagentProvider`,将每个子 agent 运行在一个派生的子进程中,并以 ACP *客户端*身份驱动它。它是现有服务端桥接 `@deepseek-ai/dsh-acp`(ACP *agent*)的方向反转孪生体:桥接应答 `initialize`/`newSession`/`prompt`;本后端调用它们并实现 `Client` 回调(`sessionUpdate`、`requestPermission`)。将配置的 spawn 命令指向 `acp-agent` 示例,即可让 harness 与自身进程通信。 ### 每次运行启动全新进程 @@ -30,7 +30,7 @@ ACP `StopReason` → harness `SubagentStopReason`:`end_turn`→`completed`、` ### 安全:清洗子进程环境 -子 agent 是独立进程,因此会继承环境变量。形如凭证的环境变量(`/KEY|SECRET|TOKEN/i`)默认**不**转发——父 harness 自身的密钥不得隐式泄露到派生进程中(与 bash 执行器采用的策略相同)。子 agent **自己**的凭证(它需要模型密钥)通过 `config.env` **显式**提供,在清洗之后叠加,因此有意传入的 `DEEPSEEK_API_KEY` 得以保留,而偶然存在的 `AWS_SECRET_ACCESS_KEY` 则不会。子进程的 stderr 继承到父进程的 stderr(诊断信息自然浮现);spawn 级别的 `error` 事件(如命令不存在时的 ENOENT)被捕获并与 ACP 驱动竞速,因此错误命令解析为 `error` 而非以未处理错误崩溃父进程。 +子 agent 是独立进程,因此会继承环境变量。形如凭证的环境变量(`/KEY|SECRET|TOKEN/i`)默认不转发——父 harness 自身的密钥不得隐式泄露到派生进程中(与 bash 执行器采用的策略相同)。子 agent 自己的凭证(它需要模型密钥)通过 `config.env` 显式提供,在清洗之后叠加,因此有意传入的 `DEEPSEEK_API_KEY` 得以保留,而偶然存在的 `AWS_SECRET_ACCESS_KEY` 则不会。子进程的 stderr 继承到父进程的 stderr(诊断信息自然浮现);spawn 级别的 `error` 事件(如命令不存在时的 ENOENT)被捕获并与 ACP 驱动竞速,因此错误命令解析为 `error` 而非以未处理错误崩溃父进程。 ## 测试 diff --git a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.i18n.yaml b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.i18n.yaml index 30f57427e2..1feca9e724 100644 --- a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-25-ask-user-question.md: 06673233038d10214f8de3d1f29766d43b575442 -2026-06-25-ask-user-question.zh.md: a036220fd54e3f634ab4be80a45964b076d3fd2d +2026-06-25-ask-user-question.md: e28d34e7b13eb8920db1eb77f4cc66aec58c3525 +2026-06-25-ask-user-question.zh.md: 86194b4eeca2761b0af412f1510a688ef48b0422 diff --git a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.md b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.md index 0667323303..e28d34e7b1 100644 --- a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.md +++ b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.md @@ -1,9 +1,9 @@ # RFC: Ask-user question capability -English | [中文](2026-06-25-ask-user-question.zh.md) - Status: implemented +English | [中文](2026-06-25-ask-user-question.zh.md) + ## Problem The agent sometimes cannot proceed safely from model inference alone: it needs the human to choose a path, confirm a risky/default action, or provide missing information. Before this change, the only way to get that answer was for the model to ask in assistant text and then stop, which broke the normal tool-call loop: the agent had no structured way to pause, no option metadata for UIs, no abort/error taxonomy, and no way for non-stdio front doors to present the question consistently. diff --git a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.zh.md b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.zh.md index a036220fd5..86194b4eec 100644 --- a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.zh.md +++ b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.zh.md @@ -1,9 +1,9 @@ -# RFC:ask-user 提问能力 - -[English](2026-06-25-ask-user-question.md) | 中文 +# RFC: ask-user 提问能力 Status: implemented +[English](2026-06-25-ask-user-question.md) | 中文 + ## 问题 agent(智能体)有时仅凭模型推理(inference)无法安全地继续执行:它需要人类选择路径、确认有风险的或默认的操作,或者提供缺失的信息。在此变更之前,获取答案的唯一方式是模型在 assistant 文本中提问然后停止,这打断了正常的工具调用循环:agent 没有结构化的暂停方式,没有供 UI 使用的选项元数据,没有中止/错误分类体系,也没有让非 stdio 前端一致地呈现问题的途径。 diff --git a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml index 677df03ea6..cacdff7448 100644 --- a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-29-todo-write-tool.md: 69f81cf6fd93df63ce53bb82c97dbac16dbbd486 -2026-06-29-todo-write-tool.zh.md: eb3c6fb8a9ddc7d26e4a620761c96a8d35ddf469 +2026-06-29-todo-write-tool.md: 7147440ec0cdb0b53093c371828d1987c17aabb0 +2026-06-29-todo-write-tool.zh.md: 7602ac8434963c84f089fe99a6f1e973c05e5bef diff --git a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.md b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.md index 69f81cf6fd..7147440ec0 100644 --- a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.md +++ b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.md @@ -1,9 +1,9 @@ # RFC: The `todo_write` tool — model task list as event-sourced session state -English | [中文](2026-06-29-todo-write-tool.zh.md) - Status: implemented +English | [中文](2026-06-29-todo-write-tool.zh.md) + ## Problem The harness gives the model bash and subagent tools but no way to record a structured task list. A todo list serves two co-equal purposes: it steers the model to plan multi-step work and keep the active task unambiguous (at most one active, exactly one while work remains), and it gives the human a live progress checklist. The ACP protocol has a native `plan` sessionUpdate that editors (Zed) already render, but the bridge never emitted one. Every reference coding agent surveyed (claude-code, opencode, codex, oh-my-pi, pi) ships some form of this; the harness had nothing. diff --git a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.zh.md b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.zh.md index eb3c6fb8a9..7602ac8434 100644 --- a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.zh.md +++ b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.zh.md @@ -1,4 +1,4 @@ -# RFC:`todo_write` 工具——将模型任务列表作为事件溯源的会话状态 +# RFC: `todo_write` 工具——将模型任务列表作为事件溯源的会话状态 Status: implemented @@ -14,7 +14,7 @@ harness 为模型提供了 bash 和 subagent 工具,却没有办法记录结 ### 整列表替换,三态 status -模型每次调用发送**完整**列表;新列表替换旧列表(回放时 last-write-wins)。这是 claude-code V1、opencode 和 codex `update_plan` 共同采用的形状,也是模型训练最多的形状——没有逐项 id,没有 delta 协议。`status` 恰好是 `pending | in_progress | completed`:与 codex `update_plan` 相同的三元组,且关键的是**与 ACP `PlanEntryStatus` 完全一致**,bridge 因此可以 1:1 映射,无需有损转换。 +模型每次调用发送完整列表;新列表替换旧列表(回放时 last-write-wins)。这是 claude-code V1、opencode 和 codex `update_plan` 共同采用的形状,也是模型训练最多的形状——没有逐项 id,没有 delta 协议。`status` 恰好是 `pending | in_progress | completed`:与 codex `update_plan` 相同的三元组,且关键的是**与 ACP `PlanEntryStatus` 完全一致**,bridge 因此可以 1:1 映射,无需有损转换。 ### 状态在会话日志上,而非服务 @@ -38,7 +38,7 @@ claude-code V1 的条目是 `{ content, status, activeForm }`;后来(V2) ### 校验:低成本的中间路线 -schema 强制 type/required/enum。在此之上,`execute` 拒绝空 `content`、重复 `content`,以及超过一个 `in_progress` 任务。claude-code 将单一 in_progress 交给 prompt 约束;oh-my-pi 在代码中强制。我们取中间路线:强制执行使计划*连贯*的低成本不变式(无空任务、无重复、最多一个活跃),但将排序和保持列表最新的纪律通过工具描述交给模型。被拒绝的写入返回 `isError` 结果,使模型自行修正。 +schema 强制 type/required/enum。在此之上,`execute` 拒绝为空或重复的 `content`,以及超过一个 `in_progress` 任务。claude-code 将单一 in_progress 交给 prompt 约束;oh-my-pi 在代码中强制。我们取中间路线:强制执行使计划*连贯*的低成本不变式(无空任务、无重复、最多一个活跃),但将排序和保持列表最新的纪律通过工具描述交给模型。被拒绝的写入返回 `isError` 结果,使模型自行修正。 ## 为何没有 cordis-catalog 条目 / 没有 `@mode` @@ -48,7 +48,7 @@ schema 强制 type/required/enum。在此之上,`execute` 拒绝空 `content` 四个层级,预先设计: - **单元测试**——会话事件(append/snapshot-clone/last-write-wins/not-on-surface);工具(schema 形状、通过真实 `ctx.tools.execute` 的参数校验、值校验、事件追加与替换、非 agent 拒绝、`presentCall`、HMR(热模块替换)安全性);ACP `todosToPlan` 映射;stdio 渲染分支。 -- **真实 Loader 路径**——插件通过 `Loader.unwrapExports` 运行,断言命名空间导出形状存活(它**有** `inject`,因此一个意外的 default 导出会在加载时崩溃——postmortem/0001)。 +- **真实 Loader 路径**——插件通过 `Loader.unwrapExports` 运行,断言命名空间导出形状存活(它有 `inject`,因此一个意外的 default 导出会在加载时崩溃——postmortem/0001)。 - **全循环集成**——一个脚本化的 mock 模型通过真实 agent loop(智能体循环)调用 `todo_write`;`todo/write` 事件落地,第二次调用替换它。 - **`session/load` 回放**——持久化的 `todo/write` 在新的 ACP bridge 加载会话时重新发出 `plan` 更新。 - **带密钥 e2e + 快照**——真实 prompt 诱导一次 `todo_write`;快照 golden 获得 `plan` 通知和日志事件。 diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.i18n.yaml index 03e276e446..fe4a29a063 100644 --- a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-30-hook-bridges.md: 17ff57307c34121c845592efa93c723e66c98886 -2026-06-30-hook-bridges.zh.md: a4b8c12593cdac35deb882ba15a58876650c1653 +2026-06-30-hook-bridges.md: c3b268bb4062c3e31acc6cdfc7641b0d1a24c47a +2026-06-30-hook-bridges.zh.md: 57ccfae2f75858254352838049516aca3668d083 diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.md b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.md index 17ff57307c..c3b268bb40 100644 --- a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.md +++ b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.md @@ -1,9 +1,9 @@ # RFC: dsh-hooks-claude + dsh-hooks-codex — the Claude Code / Codex hook bridges -English | [中文](2026-06-30-hook-bridges.zh.md) - Status: implemented +English | [中文](2026-06-30-hook-bridges.zh.md) + ## Problem The harness's extension surface is its typed interception seams ([the interception-seams RFC](2026-06-30-interception-seams.md)): a "native hook" is just an ordinary cordis plugin subscribing to `agent/session-start`, `agent/prompt-submit`, `tools/pre-execute`, `tools/post-execute`, `agent/turn-continuation`, `subagent/start`, `subagent/end`. But users arrive with **existing** Claude Code (CC) and Codex hook configs — a `hooks.json` (or a settings file's `hooks` key) full of shell-command hooks — and want those to run unmodified. This RFC introduces the two **bridge plugins** that translate that external shell-hook protocol onto the typed seams, built on the shared wire-protocol library ([the hook-protocol-lib RFC](2026-06-30-hook-protocol-lib.md)). diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.zh.md b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.zh.md index a4b8c12593..57ccfae2f7 100644 --- a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.zh.md +++ b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.zh.md @@ -1,4 +1,4 @@ -# RFC:dsh-hooks-claude + dsh-hooks-codex —— Claude Code / Codex 钩子桥接插件 +# RFC: dsh-hooks-claude + dsh-hooks-codex —— Claude Code / Codex 钩子桥接插件 Status: implemented @@ -15,7 +15,7 @@ harness 的扩展面是其类型化的拦截 seam(见[拦截 seam RFC](2026-06 `packages/hooks/` 组下两个独立插件,各为 function/namespace 插件(`name`/`inject`/`Config`/`apply`,无 default export——见 [postmortem 0001](../../../postmortem/0001-acp-default-export-drops-inject.md)),仅注入 `bash`: - **`dsh-hooks-claude`**——CC 方言。Claude Code 当前七个钩子点中的七个:`SessionStart`、`UserPromptSubmit`、`PreToolUse`、`PostToolUse`、`Stop`、`SubagentStart` 和 `SubagentStop`。拥有 CC 形态的每事件 stdin payload(基础字段 `session_id`/`cwd`/`hook_event_name` 加每事件字段)、`CLAUDE_PROJECT_DIR` 环境变量加 `${CLAUDE_PLUGIN_ROOT}`/`${CLAUDE_PROJECT_DIR}` 替换,以及字面量或正则的匹配模式。CC 钩子的 stdin 带有**尾部换行**。 -- **`dsh-hooks-codex`**——Codex 当前五个钩子点中的五个:`PreToolUse`、`PostToolUse`、`SessionStart`、`UserPromptSubmit` 和 `Stop`。使用始终为正则的匹配模式、Codex 形态的 snake_case payload(含 `turn_id`/`model`/`permission_mode` 额外字段),写入时**不带**尾部换行,不注入 Codex 插件环境变量,不做配置时占位符替换,也没有 pre-tool 审批或重写路径。工具调用的 payload 在桥接精简后的 `tool_input: { command }` 形态中携带真实的 `tool_name`。 +- **`dsh-hooks-codex`**——Codex 当前五个钩子点中的五个:`PreToolUse`、`PostToolUse`、`SessionStart`、`UserPromptSubmit` 和 `Stop`。使用始终为正则的匹配模式、Codex 形态的 snake_case payload(含 `turn_id`/`model`/`permission_mode` 额外字段),写入时不带尾部换行,不注入 Codex 插件环境变量,不做配置时占位符替换,也没有 pre-tool 审批或重写路径。工具调用的 payload 在桥接精简后的 `tool_input: { command }` 形态中携带真实的 `tool_name`。 ### Outcome → Decision 映射 diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml index 5979186c01..f745911340 100644 --- a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-30-hook-protocol-lib.md: 924c320f7ef9fdb55b20ff06f492addbf42d1720 -2026-06-30-hook-protocol-lib.zh.md: 81315cbe8767e9a3cc07cdef92359734e4e20f31 +2026-06-30-hook-protocol-lib.md: bd00c35ee2a1a1075ecae936af21508004f606b8 +2026-06-30-hook-protocol-lib.zh.md: 59b473e2a4e6f2dd95fa7bb7046848b036e5466a diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.md b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.md index 924c320f7e..bd00c35ee2 100644 --- a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.md +++ b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.md @@ -1,9 +1,9 @@ # RFC: dsh-hook-protocol — the shared Claude Code / Codex hook wire-protocol core -English | [中文](2026-06-30-hook-protocol-lib.zh.md) - Status: implemented +English | [中文](2026-06-30-hook-protocol-lib.zh.md) + ## Problem The hooks subsystem ships two bridge plugins: one that runs a user's existing Claude Code (CC) hooks, one for Codex hooks. Studying the reference implementations (`~/repos/refs/claude-code`, `~/repos/refs/codex`) surfaced a decisive fact: **Codex deliberately reimplements a SUBSET of the CC hook protocol.** Its engine reads the same `hooks.json`, uses the same matcher-group shape, the same exit-code/structured-stdout output contract, and the same command-hook execution model — Codex's source even names the engine after Claude's and comments where it "intentionally diverges." So the two bridges would otherwise duplicate the bulk of the protocol. diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.zh.md b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.zh.md index 81315cbe87..59b473e2a4 100644 --- a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.zh.md +++ b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.zh.md @@ -1,9 +1,9 @@ -# RFC:dsh-hook-protocol——Claude Code / Codex 钩子协议格式共享核心库 - -[English](2026-06-30-hook-protocol-lib.md) | 中文 +# RFC: dsh-hook-protocol——Claude Code / Codex 钩子协议格式共享核心库 Status: implemented +[English](2026-06-30-hook-protocol-lib.md) | 中文 + ## 问题 hooks 子系统提供两个桥接插件:一个运行用户既有的 Claude Code(CC)钩子,另一个运行 Codex 钩子。研究参考实现(`~/repos/refs/claude-code`、`~/repos/refs/codex`)后发现一个决定性事实:**Codex 有意重新实现了 CC 钩子协议的一个子集。** 它的引擎读取相同的 `hooks.json`,使用相同的 matcher-group 形状、相同的 exit-code/structured-stdout 输出契约,以及相同的 command-hook 执行模型。Codex 的源码甚至以 Claude 的引擎命名,并在注释中标注了"有意偏离"之处。因此,如果不做抽取,两个桥接插件将大量重复协议逻辑。 @@ -16,7 +16,7 @@ hooks 子系统提供两个桥接插件:一个运行用户既有的 Claude Cod **共享(本库):** - **Matcher** — `matchesMatcher(pattern, query, mode)`。两种方言唯一不同的轴被收敛为 `mode` 参数:`claude` 将纯 `[A-Za-z0-9_|]+` 模式视为字面量(管道符 = 精确匹配的多选),其余视为正则;`codex` 始终是无锚定正则。缺省/`''`/`'*'` 匹配一切;无效正则匹配空集(绝不向 agent loop(智能体循环)抛异常)。 -- **Execution** — `runHook(bash, hook, options)`。通过 `ctx.bash` seam 而非自建 spawn 运行 command hook:执行器已提供清洗但可覆盖的 env、进程组 kill 和超时,正是协议所需的能力;`dsh-bash` 的 `stdin`/`env` 字段(正是为此添加的)是进程内桥接插件被允许使用的受信插件接口。它将桥接插件构建的 payload 序列化到 stdin(CC 时追加尾部换行),遵守钩子的 `timeoutSec`(否则使用 `DEFAULT_HOOK_TIMEOUT_MS`,即两种方言共享的 10 分钟参考默认值),且从不抛异常(执行器拒绝变为 non-blocking-error 的 `HookOutput`)。 +- **Execution** — `runHook(bash, hook, options)`。通过 `ctx.bash` seam 而非自建 `spawn` 运行 command hook:执行器已提供清洗但可覆盖的 env、进程组 kill 和超时,正是协议所需的能力;`dsh-bash` 的 `stdin`/`env` 字段(正是为此添加的)是进程内桥接插件被允许使用的受信插件接口。它将桥接插件构建的 payload 序列化到 stdin(CC 时追加尾部换行),遵守钩子的 `timeoutSec`(否则使用 `DEFAULT_HOOK_TIMEOUT_MS`,即两种方言共享的 10 分钟参考默认值),且从不抛异常(执行器拒绝变为 non-blocking-error 的 `HookOutput`)。 - **Decode** — `parseHookOutput(exit, stdout, stderr)`,exit-code + structured-stdout 编解码器,产出方言无关的 `HookOutput`。Exit `0` → 宽松 JSON 解析 stdout;exit `2` → blocking error,`stderr` 为原因(以 `decision: 'block'` 呈现,调用方无需单独处理 exit-code 分支);其他 → non-blocking error。解析 CC structured-stdout 中在某条路径上有消费方的字段(`continue`/`stopReason`/`decision`/`hookSpecificOutput.{permissionDecision,additionalContext,updatedInput}`/`systemMessage`);桥接插件只采纳对其方言有意义的子集。在任何路径上都没有消费方的字段不予解析(CC 的 `suppressOutput`——钩子 stdout 在此处从不进入 transcript(文本记录),因此无需抑制;见 [tighten-hook-protocol-contract RFC](../simplification/2026-07-04-tighten-hook-protocol-contract.md))。 - **Merge** — `mergeHookOutputs(outputs)`,将多个匹配钩子的输出折叠为一个最严格的 `MergedHookOutcome`:权限优先级 **deny > ask > allow**,halt 在首个 `continue:false` 时粘滞,block reason 以 `\n\n` 拼接,context/system-messages 按序累积。 - **`hook/*` 会话事件** — `hook/invoked` / `hook/result`,declaration-merge 进 `SessionEventMap`(仅日志,如 `compact/*`——不是 `SurfaceEventType`),配有 `appendHookInvoked`/`appendHookResult` 辅助函数,确保 invoked/result 配对与 turn 包含关系在各桥接插件间保持一致。`appendHookResult` 还拥有持久化记录的语义:decision 字符串(钩子解析出的 decision,否则 `continue:false` 时为 `'stop'`,否则为 `'pass'`)和 500 字符的 `stderrSummary` 截断均从本库的 `HookOutput` 派生,而非各桥接插件各自实现。 diff --git a/docs/rfc/implemented/feature/2026-06-30-interception-seams.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-interception-seams.i18n.yaml index 2a1efb261c..1079a59599 100644 --- a/docs/rfc/implemented/feature/2026-06-30-interception-seams.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-30-interception-seams.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-30-interception-seams.md: fb8efe1e1c2057db13b440881f110ca7f579a81e -2026-06-30-interception-seams.zh.md: 668b96dba282ecdcbe85cc0b1dc56c2de293b3b3 +2026-06-30-interception-seams.md: 66e1c2374936c794bd5f791547c283f0fb59fb23 +2026-06-30-interception-seams.zh.md: fb2f1528a8e72a2f6b8b07679c8631b1b0a4f2d8 diff --git a/docs/rfc/implemented/feature/2026-06-30-interception-seams.md b/docs/rfc/implemented/feature/2026-06-30-interception-seams.md index fb8efe1e1c..66e1c23749 100644 --- a/docs/rfc/implemented/feature/2026-06-30-interception-seams.md +++ b/docs/rfc/implemented/feature/2026-06-30-interception-seams.md @@ -1,9 +1,9 @@ # RFC: Interception seams — the typed-Decision surface a hook programs against -English | [中文](2026-06-30-interception-seams.zh.md) - Status: implemented +English | [中文](2026-06-30-interception-seams.zh.md) + ## Problem The harness needs a hooks subsystem: users extend or gate the agent at lifecycle points the way Claude Code (CC) and Codex do. The key reframe driving this design is that **"native hooks" are not a package** — a native hook is just an ordinary Cordis plugin subscribing to the canonical lifecycle events. So the real product is a *powerful, well-typed canonical event surface*; the CC/Codex bridges (the `dsh-hooks-claude` / `dsh-hooks-codex` packages) are merely translators that map an external shell-hook protocol onto that same surface. Anything a bridge can do, a plain plugin can do directly — more powerfully (no serialization boundary, full `ctx`, typed returns). diff --git a/docs/rfc/implemented/feature/2026-06-30-interception-seams.zh.md b/docs/rfc/implemented/feature/2026-06-30-interception-seams.zh.md index 668b96dba2..fb2f1528a8 100644 --- a/docs/rfc/implemented/feature/2026-06-30-interception-seams.zh.md +++ b/docs/rfc/implemented/feature/2026-06-30-interception-seams.zh.md @@ -1,4 +1,4 @@ -# RFC:拦截 seam——钩子编程所面对的类型化 Decision 表面 +# RFC: 拦截 seam——钩子编程所面对的类型化 Decision 表面 Status: implemented @@ -15,7 +15,7 @@ harness 需要一套钩子子系统:用户像 Claude Code(CC)和 Codex 那 规范表面将可变换策略、环绕调度控制与仅观测通知分离。策略 waterfall(瀑布式事件)返回小型的、seam 专属的**类型化 Decision 联合类型**;包装层返回规范化结果;通知接收不可变快照,无法影响结果。覆盖的钩子点包括 `session-start`、`prompt-submit`、`pre-tool`、`post-tool`、通过 continuation 实现的 `stop`,同时将非钩子的执行策略留作独立可组合。 **Agent 事件**(`dsh-agent`): -- `agent/session-start(agent, source)` ——emit,在第 1 轮次之前触发一次,携带 `SessionStartSource`(`startup` 表示全新/fork 创建,`resume` 表示重新加载的持久化会话;`clear`/`compact` 保留)。纯通知,**不能**阻塞启动(这是有意的空白:桥接可以记录/注入,但不管控启动)。监听器通过 `agent.inject()` 注入上下文。 +- `agent/session-start(agent, source)` ——emit,在第 1 轮次之前触发一次,携带 `SessionStartSource`(`startup` 表示全新/fork 创建,`resume` 表示重新加载的持久化会话;`clear`/`compact` 保留)。纯通知,不能阻塞启动(这是有意的空白:桥接可以记录/注入,但不管控启动)。监听器通过 `agent.inject()` 注入上下文。 - `agent/prompt-submit(agent, content, source, next) → PromptDecision` ——waterfall,在已开启的轮次内、`user/message` 追加之前,对每条出队的排队消息触发。`allow`(可选地重写 prompt `content` 或附加 `additionalContext`)或 `block`(丢弃该 prompt;循环在其位置追加一条持久的 `prompt/blocked`——见下方调度说明)。 **`agent/turn-continuation`** 接收并返回一个 `ContinuationDecision`。`{action:'continue', reason?}` 可携带面向模型的上下文,记录为同一轮次内的下一步 steering(中途引导)——与 `/goal` step-end-steer 模式互为类型化孪生。 @@ -38,7 +38,7 @@ harness 需要一套钩子子系统:用户像 Claude Code(CC)和 Codex 那 1. **在 prompt 策略之前开启轮次。** 全部被阻止的批次成为零步骤的 `rejected` 轮次,保持封闭性并为 ACP(Agent Client Protocol)提供持久的终结事件。每次否决还记录 `prompt/blocked`(含原始 prompt 和原因),因此混合批次保留被阻止的输入。允许的 `additionalContext` 注入到已开启的轮次中。 -2. **Post-tool `additionalContext` 被缓冲,在所有 `tool/result` 之后追加。** `content`/`feedback` 塑造 `execute()` 返回的结果,但 `additionalContext` 是一条**独立的** `context/message`,而单个步骤可以携带多个工具调用。如果在每个结果之后立即追加上下文,会产生 `result(c1) → context → result(c2)` 的交错,破坏工具调用/结果的邻接性。因此 `execute()` 将 `additionalContext` 暴露在其 `ToolExecutionResult` 上,循环为该步骤的每次调用缓冲上下文,仅在所有 `tool/result` 追加完毕后才以 `context/message` 形式追加。 +2. **Post-tool `additionalContext` 被缓冲,在所有 `tool/result` 之后追加。** `content`/`feedback` 塑造 `execute()` 返回的结果,但 `additionalContext` 是一条独立的 `context/message`,而单个步骤可以携带多个工具调用。如果在每个结果之后立即追加上下文,会产生 `result(c1) → context → result(c2)` 的交错,破坏工具调用/结果的邻接性。因此 `execute()` 将 `additionalContext` 暴露在其 `ToolExecutionResult` 上,循环为该步骤的每次调用缓冲上下文,仅在所有 `tool/result` 追加完毕后才以 `context/message` 形式追加。 3. **强制 `continue` 的 `reason` 通过 steering 通道入队**,使得下一步骤在循环顶部排空时将其记录为当前轮次的 steering——同一轮次内的下一*步骤* steering,而非下一*轮次*的 prompt(与现有的 `hasSteering` 强制继续覆盖一致)。 diff --git a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml index c05a025ca6..b06ccc29d9 100644 --- a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-30-session-store-fork-api.md: 4bf5c3fe43821570fd947034358e54d0a0a602f9 -2026-06-30-session-store-fork-api.zh.md: a3ffb881a446647861fa5fbaf57dde291838a090 +2026-06-30-session-store-fork-api.md: c5359a30124aabf0f9f809ffe899c6ad5fca8051 +2026-06-30-session-store-fork-api.zh.md: 62f399df41488143a66069fdd5a36ddb3e62421f diff --git a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.md b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.md index 4bf5c3fe43..c5359a3012 100644 --- a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.md +++ b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.md @@ -1,9 +1,9 @@ # RFC: SessionStore fork API -English | [中文](2026-06-30-session-store-fork-api.zh.md) - Status: implemented +English | [中文](2026-06-30-session-store-fork-api.zh.md) + ## Problem The event-sourced session log already has the primitive a fork needs: create a new session with a seed event prefix, then derive model history from that seeded log exactly as replay does. That primitive is intentionally low-level: `ctx.sessions.create(id, { seed, meta })` accepts any valid seed, but ordinary live-session branching needs policy around which prefix can be copied, which metadata is stamped on the child, and how errors are classified. diff --git a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.zh.md b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.zh.md index a3ffb881a4..62f399df41 100644 --- a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.zh.md +++ b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.zh.md @@ -1,9 +1,9 @@ -# RFC:SessionStore fork API - -[English](2026-06-30-session-store-fork-api.md) | 中文 +# RFC: SessionStore fork API Status: implemented +[English](2026-06-30-session-store-fork-api.md) | 中文 + ## 问题 事件溯源的会话日志已经具备 fork 所需的原语:创建一个带有种子事件前缀的新会话,然后像回放一样从该种子日志推导模型历史。这个原语有意保持底层:`ctx.sessions.create(id, { seed, meta })` 接受任何合法种子,但常规的活跃会话分支需要围绕以下问题制定策略:哪些前缀可以被复制、子会话应打上哪些元数据、以及错误如何分类。 diff --git a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml index 90b6939da2..cb9c05d033 100644 --- a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-30-subagent-observe-enrich.md: b48a1fff32130345e669a3b3b905c4fda987e41e -2026-06-30-subagent-observe-enrich.zh.md: 8ce070001e219572658fd4e94c660de1094ddee5 +2026-06-30-subagent-observe-enrich.md: 1e20ddff5473a23f3ed560246fbd06f8090852ae +2026-06-30-subagent-observe-enrich.zh.md: 6bc00c9a8f1d3656fbbfc482e3e6b66020298dd9 diff --git a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.md b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.md index b48a1fff32..1e20ddff54 100644 --- a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.md +++ b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.md @@ -1,9 +1,9 @@ # RFC: Subagent lifecycle enrichment — lastAssistantMessage (observe-only) -English | [中文](2026-06-30-subagent-observe-enrich.zh.md) - Status: implemented +English | [中文](2026-06-30-subagent-observe-enrich.zh.md) + ## Problem The hooks subsystem ([interception seams RFC](2026-06-30-interception-seams.md)) lets a plugin observe and gate the agent at lifecycle points. Claude Code and Codex both expose **SubagentStart / SubagentStop** hooks, and CC's carry the subagent's final message. The harness already emits `subagent/start` and `subagent/end` lifecycle events ([the subagent capability-seam](2026-06-21-subagent-capability-seam.md)), but their payloads were minimal (`provider`, `id`, and on end `stopReason`) — not enough for a hooks bridge to report WHAT a subagent produced without separately reaching for the live run. diff --git a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md index 8ce070001e..6bc00c9a8f 100644 --- a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md +++ b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md @@ -1,4 +1,4 @@ -# RFC:Subagent 生命周期丰富化——lastAssistantMessage(仅观察) +# RFC: Subagent 生命周期丰富化——lastAssistantMessage(仅观察) Status: implemented diff --git a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml index 25c723bde1..bcf9d40b91 100644 --- a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-05-dynamic-workflows.md: 67ceebf7017f197bd800fd339b575390b3b936c1 -2026-07-05-dynamic-workflows.zh.md: 54ba0d903de228e14a53e6f64ead0f5156e61289 +2026-07-05-dynamic-workflows.md: e6f2ab9a4fc5f5403a7739495be7d82ebce3ec0d +2026-07-05-dynamic-workflows.zh.md: 82234c2405f972f2c42c58be6772f55eda500455 diff --git a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md index 67ceebf701..e6f2ab9a4f 100644 --- a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md +++ b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md @@ -1,9 +1,9 @@ # RFC: Dynamic workflows — a script-driven multi-agent orchestration seam -English | [中文](2026-07-05-dynamic-workflows.zh.md) - Status: implemented +English | [中文](2026-07-05-dynamic-workflows.zh.md) + ## Problem The harness can delegate ONE task to ONE child (`dsh-tool-subagent`), but work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — forces the model to orchestrate turn by turn: every intermediate result lands in the parent context, the plan lives nowhere durable, and coordination costs a model round-trip per step. Claude Code ships this capability as [dynamic workflows](https://code.claude.com/docs/en/workflows): the model writes a JavaScript orchestration script, a runtime executes it, and the script — not the conversation — holds the loop, the branching, and the intermediate results. diff --git a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.zh.md b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.zh.md index 54ba0d903d..82234c2405 100644 --- a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.zh.md +++ b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.zh.md @@ -1,9 +1,9 @@ -# RFC:动态工作流——脚本驱动的多 agent 编排 seam - -[English](2026-07-05-dynamic-workflows.md) | 中文 +# RFC: 动态工作流——脚本驱动的多 agent 编排 seam Status: implemented +[English](2026-07-05-dynamic-workflows.md) | 中文 + ## 问题 harness 可以将一个任务委派给一个子 agent(`dsh-tool-subagent`),但需要扇出到多个独立部分的工作——跨多文件审计、迁移、多角度调研、对抗式验证——迫使模型逐轮次编排:每个中间结果都落入父上下文,计划无处持久存储,每一步的协调都要消耗一次模型往返。Claude Code 以 [dynamic workflows](https://code.claude.com/docs/en/workflows) 的形式提供了这一能力:模型编写一段 JavaScript 编排脚本,运行时执行它,由脚本(而非对话)持有循环、分支和中间结果。 @@ -16,11 +16,11 @@ harness 可以将一个任务委派给一个子 agent(`dsh-tool-subagent`) 一次工作流调用包含 JSON `meta`(`name`、`description`,以及可选的 `whenToUse`/`phases`)和一段支持顶层 `await` 并返回 JSON 值的 JavaScript `script` 正文。元数据作为数据校验,从不被执行。正文接收 `agent(prompt, options)`、`parallel(thunks)`、`pipeline(items, ...stages)`、`phase(title)`、`log(message)` 和 `args`。pipeline 各阶段接收 `(prev, item, index)`,阶段之间无屏障;失败的子 agent 和普通阶段错误将受影响的 item 解析为 `null` 并跳过其剩余阶段。Claude Code 的确定性限制通过日志化延迟处理,因此兼容的脚本正文在将 meta 头移入参数后可以使用时钟和随机数。 -与 CC 有一处刻意的严格性**差异**:钩子误用——未知或延迟的选项(`effort`/`isolation`/`agentType`)、格式错误的参数、超出支持子集的 schema、触发上限、seam 启动失败——会抛出带 `fatal: true` 的 `WorkflowError`,组合器会**重新抛出** fatal 错误而非将 item 置为 null。如果不这样做,一个拼错的选项会悄然变成一个与子 agent 失败无法区分的 `null`——这正是本仓库禁止的「被接受后被忽略」的失败模式。另有一处新增:工具的 `args` 参数是一个 JSON **对象**(裸列表被包装为一个字段),使协议格式(wire format)保持诚实。 +与 CC 有一处刻意的严格性差异:钩子误用——未知或延迟的选项(`effort`/`isolation`/`agentType`)、格式错误的参数、超出支持子集的 schema、触发上限、seam 启动失败——会抛出带 `fatal: true` 的 `WorkflowError`,组合器会重新抛出 fatal 错误而非将 item 置为 null。如果不这样做,一个拼错的选项会悄然变成一个与子 agent 失败无法区分的 `null`——这正是本仓库禁止的「被接受后被忽略」的失败模式。另有一处新增:工具的 `args` 参数是一个 JSON 对象(裸列表被包装为一个字段),使协议格式(wire format)保持诚实。 ### seam(dsh-workflow) -`ctx.workflows` 是 bash 形态的抽象 `WorkflowService`——每个上下文一个引擎,无命名提供方注册表(引擎是部署级替换,不是共存者)。`start(request)` 对无法启动的脚本同步抛出;返回的 `WorkflowRun` 的 `result` **永不** reject(失败解析为 `stopReason: 'error' | 'cancelled'`)。`workflow/*` 事件是仅观察的 emit,携带**数据快照**(id + meta;`workflow/end` 省略 result 值),按监听器隔离,与 `subagent/start`/`subagent/end` 对称——控制权留在 run 的持有者手中。词汇详情见 [core-data-structures/workflow.md](../../../core-data-structures/workflow.md)。 +`ctx.workflows` 是 bash 形态的抽象 `WorkflowService`——每个上下文一个引擎,无命名提供方注册表(引擎是部署级替换,不是共存者)。`start(request)` 对无法启动的脚本同步抛出;返回的 `WorkflowRun` 的 `result` 永不 reject(失败解析为 `stopReason: 'error' | 'cancelled'`)。`workflow/*` 事件是仅观察的 emit,携带数据快照(id + meta;`workflow/end` 省略 result 值),按监听器隔离,与 `subagent/start`/`subagent/end` 对称——控制权留在 run 的持有者手中。词汇详情见 [core-data-structures/workflow.md](../../../core-data-structures/workflow.md)。 ### 引擎(dsh-workflow-workerthread):每次运行一个 worker 线程 @@ -38,7 +38,7 @@ harness 可以将一个任务委派给一个子 agent(`dsh-tool-subagent`) ### 消费方(dsh-tool-workflow) -一个 `workflow` 工具,镜像 `dsh-tool-subagent` 的同步形态:启动、await、`try/finally` dispose、abort 桥接 `exec.signal`、非 `completed` → `isError`。渲染意图:一张以调用的 `meta.name` 参数为标题的 `generic` 卡片(展示是参数的纯函数)。工具描述**即**面向模型的编写规范。使用策略以工具自身的 `tool:` prompt 段落随工具发布(显式请求才使用的引导——工具引导存在于工具插件中,从不在部署 persona 中);harness 没有 ultracode 风格的 effort 门控。 +一个 `workflow` 工具,镜像 `dsh-tool-subagent` 的同步形态:启动、await、`try/finally` dispose、abort 桥接 `exec.signal`、非 `completed` → `isError`。渲染意图:一张以调用的 `meta.name` 参数为标题的 `generic` 卡片(展示是参数的纯函数)。工具描述即面向模型的编写规范。使用策略以工具自身的 `tool:` prompt 段落随工具发布(显式请求才使用的引导——工具引导存在于工具插件中,从不在部署 persona 中);harness 没有 ultracode 风格的 effort 门控。 ### 基础:subagent seam 上的结构化输出 diff --git a/docs/rfc/implemented/feature/2026-07-05-skill-system.i18n.yaml b/docs/rfc/implemented/feature/2026-07-05-skill-system.i18n.yaml index 3b3aed7c50..31fb9e006f 100644 --- a/docs/rfc/implemented/feature/2026-07-05-skill-system.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-05-skill-system.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-05-skill-system.md: 6cfd1f977ae5a1e1ad646a707a4201e57d46bc38 -2026-07-05-skill-system.zh.md: f59fd5d850a38d7324b391a116c72c4e71ef7401 +2026-07-05-skill-system.md: f39b5f5766eadf7c0a7bfd3f887aca60f69477af +2026-07-05-skill-system.zh.md: 0aff262792a6f8a38a02475d6975510d5aae5da5 diff --git a/docs/rfc/implemented/feature/2026-07-05-skill-system.md b/docs/rfc/implemented/feature/2026-07-05-skill-system.md index 6cfd1f977a..f39b5f5766 100644 --- a/docs/rfc/implemented/feature/2026-07-05-skill-system.md +++ b/docs/rfc/implemented/feature/2026-07-05-skill-system.md @@ -1,9 +1,9 @@ # RFC: Skill system — progressive disclosure instructions for agents -English | [中文](2026-07-05-skill-system.zh.md) - Status: implemented +English | [中文](2026-07-05-skill-system.zh.md) + ## Problem Agent products have converged on a skill pattern: keep the request prompt small by listing only available instruction bundles, then load the full body when the model decides a task matches. Codex, Claude Code, OpenCode, and Kimi Code differ in details, but all separate discovery metadata from complete instructions so a workspace can carry reusable behavior without paying the full prompt cost on every turn. diff --git a/docs/rfc/implemented/feature/2026-07-05-skill-system.zh.md b/docs/rfc/implemented/feature/2026-07-05-skill-system.zh.md index f59fd5d850..0aff262792 100644 --- a/docs/rfc/implemented/feature/2026-07-05-skill-system.zh.md +++ b/docs/rfc/implemented/feature/2026-07-05-skill-system.zh.md @@ -1,9 +1,9 @@ -# RFC:Skill 系统——面向 agent 的渐进式指令披露 - -[English](2026-07-05-skill-system.md) | 中文 +# RFC: Skill 系统——面向 agent 的渐进式指令披露 Status: implemented +[English](2026-07-05-skill-system.md) | 中文 + ## 问题 Agent(智能体)产品已趋同于一种 skill(技能)模式:保持请求提示词精简,仅列出可用的指令包,当模型判定某任务匹配时再加载完整正文。Codex、Claude Code、OpenCode 与 Kimi Code 在细节上各有不同,但都将发现元数据与完整指令分离,使工作区能承载可复用的行为而无需在每个轮次支付全量提示词开销。 diff --git a/docs/rfc/implemented/feature/2026-07-06-approval-seam.i18n.yaml b/docs/rfc/implemented/feature/2026-07-06-approval-seam.i18n.yaml index 8d7fa05dfc..fe71c00352 100644 --- a/docs/rfc/implemented/feature/2026-07-06-approval-seam.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-06-approval-seam.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-06-approval-seam.md: 3ef51c31216bf9f0c5d945748ab3f901ec82147c -2026-07-06-approval-seam.zh.md: 1bf679426a434c36f5363c3b70f13a8f24534df3 +2026-07-06-approval-seam.md: dedcc2022382af7a614023e4354b77f1c15cd92f +2026-07-06-approval-seam.zh.md: 193461a2e5c3c14efe4b1565656cc38baab11fcb diff --git a/docs/rfc/implemented/feature/2026-07-06-approval-seam.md b/docs/rfc/implemented/feature/2026-07-06-approval-seam.md index 3ef51c3121..dedcc20223 100644 --- a/docs/rfc/implemented/feature/2026-07-06-approval-seam.md +++ b/docs/rfc/implemented/feature/2026-07-06-approval-seam.md @@ -1,9 +1,9 @@ # RFC: The approval seam — one-shot permission decisions over a waterfall of answerers -English | [中文](2026-07-06-approval-seam.zh.md) - Status: implemented +English | [中文](2026-07-06-approval-seam.zh.md) + ## Problem Two callers need to put one question — "may this specific action proceed?" — to a human: `tools/pre-execute`'s `ask` decision (including the Claude-Code hook bridge's `permissionDecision: ask`) and the [sandbox RFC](2026-07-06-sandbox.md)'s post-denial one-shot escalation retry. A shared seam keeps them from inventing separate outcome vocabularies, UI routing, cancellation, and audit trails, while guaranteeing that a deployment with no UI can never grant an unanswerable request. diff --git a/docs/rfc/implemented/feature/2026-07-06-approval-seam.zh.md b/docs/rfc/implemented/feature/2026-07-06-approval-seam.zh.md index 1bf679426a..193461a2e5 100644 --- a/docs/rfc/implemented/feature/2026-07-06-approval-seam.zh.md +++ b/docs/rfc/implemented/feature/2026-07-06-approval-seam.zh.md @@ -1,4 +1,4 @@ -# RFC:审批 seam——基于 waterfall(瀑布式事件)应答者的一次性权限决策 +# RFC: 审批 seam——基于 waterfall(瀑布式事件)应答者的一次性权限决策 Status: implemented @@ -12,7 +12,7 @@ Status: implemented ## 决策 -一个包 `dsh-user-approval`(`packages/ui/user-approval`),拥有词汇表和 `ctx.approval` 服务——即**机制**。**策略**——谁来应答、某个会话是否需要被询问——不在其中:应答者是 `approval/request` waterfall 监听器,由拥有通道的插件注册(ACP 桥、未来的终端 UI、测试脚本),而每会话的策略层可以在任何人类介入之前做出决定。消费方(`dsh-tools` 的 ask 路由、沙箱升级门禁)将问题解析为一个封闭结果,并从中派生各自的工具结果。刻意设计为**一个**包,而非能力 seam 的三包拆分(见「替代方案」)。 +一个包 `dsh-user-approval`(`packages/ui/user-approval`),拥有词汇表和 `ctx.approval` 服务——即机制。策略——谁来应答、某个会话是否需要被询问——不在其中:应答者是 `approval/request` waterfall 监听器,由拥有通道的插件注册(ACP 桥、未来的终端 UI、测试脚本),而每会话的策略层可以在任何人类介入之前做出决定。消费方(`dsh-tools` 的 ask 路由、沙箱升级门禁)将问题解析为一个封闭结果,并从中派生各自的工具结果。刻意设计为一个包,而非能力 seam 的三包拆分(见「替代方案」)。 ### 部署如何使用它 @@ -95,7 +95,7 @@ ACP 桥找到拥有该会话的编辑器,为该 `callId` 发送 `session/reque ## 曾考虑的替代方案 - **单一注册提供方而非 waterfall 监听器**:否决。`registerProvider()` 接口迫使所有组合问题——允许列表预过滤、外部钩子决策者、脚本化测试应答、人类前面的策略门禁——都塞进一个提供方实现。waterfall 从运行时已有的机制中获得组合能力、缺失时失败关闭和 HMR(热模块替换) dispose(资源释放);seam 的 JSDoc 以约定固定单决策槽语义,而非发明一个提供方注册表。 -- **在 ACP 桥中内联 `tools/pre-execute` 权限门禁**:否决。对桥拥有的每次调用都弹出提示,会将请求**策略**硬编码进 UI 插件,无法服务第二个发起方(沙箱升级发生在执行开始之后,没有 pre-execute 时刻),且钩子产生的 `ask` 决策没有共享机制。 +- **在 ACP 桥中内联 `tools/pre-execute` 权限门禁**:否决。对桥拥有的每次调用都弹出提示,会将请求策略硬编码进 UI 插件,无法服务第二个发起方(沙箱升级发生在执行开始之后,没有 pre-execute 时刻),且钩子产生的 `ask` 决策没有共享机制。 - **通用用户交互 seam(`ctx.userInteraction`)**:否决作为审批机制。二者骨架相似(按 agent 路由、阻塞等待人类、处理缺失),但审批的契约在每个关键维度上都更窄:封闭的结果词汇而非自由文本、附着在工具调用上的协议原生提示而非通用表单、强制的缺失时失败关闭、以及审计事件。因此审批不走已交付的 `packages/ui/user-interaction` / `ask_user_question` 引出路径——引出表单不是权限提示,自由文本应答不是封闭结果;如果二者将来趋同,共享提供方管道仍然开放。 - **`dsh-tools` 中的静态可选注入**:否决。vendor 的 Cordis `Inject` 类型没有 optional 标志——对象形式将服务名映射到拦截配置,声明的 inject 会阻塞 fiber。`ctx.get('approval')` 是文档化的机会性消费模式(`tool-bash` 的 owner-token 查找、loop 的持久化探测),按调用读取存在性,跨 HMR 正确降级,无需额外机制。 - **能力 seam 的三包拆分**:否决。接口/实现/消费方适合实现可替换的 seam(bash-local vs bash-sandbox)。此处服务体是固定机制,可变部分是留在各自通道拥有者插件中的监听器——拆分只会制造一个空的实现包(「不要预防性拆分」)。 diff --git a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml index 0e418c8e57..53215fce5e 100644 --- a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-06-explicit-tool-order.md: 9d94496ffdcbc4c7df820581b02e3e075ec1c0be -2026-07-06-explicit-tool-order.zh.md: 0b020f969299799289e18ed93c81db08cabc0b2d +2026-07-06-explicit-tool-order.md: b5f37239efc856866f08d93ab80eba91145a34db +2026-07-06-explicit-tool-order.zh.md: eca75499c2505c9cac0135ddb2ffc8cdd989b100 diff --git a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md index 9d94496ffd..b5f37239ef 100644 --- a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md +++ b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md @@ -1,9 +1,9 @@ # RFC: Explicit model-facing tool order -English | [中文](2026-07-06-explicit-tool-order.zh.md) - Status: implemented +English | [中文](2026-07-06-explicit-tool-order.zh.md) + ## Problem Model-facing tool order followed plugin registration order, which depends on concurrent module loading for otherwise independent plugins. That race produced different request headers in CI and snapshot recordings. Because order affects request bytes, caching, and the durable header, it needs an explicit deterministic policy. diff --git a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.zh.md b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.zh.md index 0b020f9692..eca75499c2 100644 --- a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.zh.md +++ b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.zh.md @@ -1,9 +1,9 @@ -# RFC:显式的模型侧工具顺序 - -[English](2026-07-06-explicit-tool-order.md) | 中文 +# RFC: 显式的模型侧工具顺序 Status: implemented +[English](2026-07-06-explicit-tool-order.md) | 中文 + ## 问题 模型侧的工具顺序此前跟随插件注册顺序,而注册顺序取决于相互独立的插件的并发模块加载。这种竞态在 CI 和快照录制中产生了不同的请求头。由于顺序影响请求字节、缓存和持久化的 header,因此需要一个显式的确定性策略。 diff --git a/docs/rfc/implemented/feature/2026-07-06-sandbox.i18n.yaml b/docs/rfc/implemented/feature/2026-07-06-sandbox.i18n.yaml index 8c97f0b5ee..87137ea20f 100644 --- a/docs/rfc/implemented/feature/2026-07-06-sandbox.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-06-sandbox.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-06-sandbox.md: 29985b9336e7a190c90dc0e9c3b3aa78b6197e8e -2026-07-06-sandbox.zh.md: 4285ae4ceb81ee57dc3ab3d51467f9267743e06e +2026-07-06-sandbox.md: 0df97717c9166d5160189c840b108acecd3d3291 +2026-07-06-sandbox.zh.md: 164e44f6b7c84d8f279b0146cc3c74299a51d1fa diff --git a/docs/rfc/implemented/feature/2026-07-06-sandbox.md b/docs/rfc/implemented/feature/2026-07-06-sandbox.md index 29985b9336..0df97717c9 100644 --- a/docs/rfc/implemented/feature/2026-07-06-sandbox.md +++ b/docs/rfc/implemented/feature/2026-07-06-sandbox.md @@ -1,9 +1,9 @@ # RFC: The subprocess sandbox — confinement seam, native runners, escalation, and per-session modes -English | [中文](2026-07-06-sandbox.zh.md) - Status: implemented +English | [中文](2026-07-06-sandbox.zh.md) + ## Problem A coding agent needs this product path: bash subprocesses — and the hook commands that ride them — execute under a restricted file sandbox by default; if and only if the sandbox actually denies an operation, the model may request one user approval for that same operation and, once granted, retry it once with wider permissions. An every-tool boundary is deliberately NOT the claim: fs/web/todo execute in-process where an `execve` wrapper is meaningless (§ In-process tools), and the cross-family boundary is staged follow-up work (§ Deferred phases). Without a shared vocabulary, every tool reinvents approval fields, denial parsing, retry matching, and permission-state hints. diff --git a/docs/rfc/implemented/feature/2026-07-06-sandbox.zh.md b/docs/rfc/implemented/feature/2026-07-06-sandbox.zh.md index 4285ae4ceb..164e44f6b7 100644 --- a/docs/rfc/implemented/feature/2026-07-06-sandbox.zh.md +++ b/docs/rfc/implemented/feature/2026-07-06-sandbox.zh.md @@ -1,4 +1,4 @@ -# RFC:子进程沙箱——约束 seam、原生 runner、升级机制与按会话模式 +# RFC: 子进程沙箱——约束 seam、原生 runner、升级机制与按会话模式 Status: implemented @@ -8,7 +8,7 @@ Status: implemented 一个编码 agent 需要如下产品路径:bash 子进程(以及依附其上的钩子命令)默认在受限的文件沙箱下执行;当且仅当沙箱实际拒绝了某个操作时,模型可以为同一操作请求一次用户批准,获批后以更宽的权限重试一次。本设计刻意不声称覆盖所有工具:fs/web/todo 在进程内执行,`execve` 包装对它们毫无意义(§ 进程内工具);跨工具族的统一边界属于分阶段后续工作(§ 延迟阶段)。如果没有共享词汇,每个工具都会各自重新发明批准字段、拒绝解析、重试匹配和权限状态提示。 -harness 是一个 SDK,因此约束必须是开发者可**组合**的能力:是否启用沙箱、每个平台使用哪个后端,都应作为一等条目写在叶子 `cordis.yml` 中,而非藏在某个执行器的私有机制里。而首选 runner `bwrap` 恰恰在沙箱最重要的主机上不可用(精简容器、禁用了非特权 userns、LSM 拒绝 `mount`),因此备选 runner 必须随 SDK 一起交付,而不能假设主机已有。 +harness 是一个 SDK,因此约束必须是开发者可组合的能力:是否启用沙箱、每个平台使用哪个后端,都应作为一等条目写在叶子 `cordis.yml` 中,而非藏在某个执行器的私有机制里。而首选 runner `bwrap` 恰恰在沙箱最重要的主机上不可用(精简容器、禁用了非特权 userns、LSM 拒绝 `mount`),因此备选 runner 必须随 SDK 一起交付,而不能假设主机已有。 仅有约束还留下两个缺口。拒绝后没有升级路径就是死路:模型只能放弃,这会迫使运维人员全局配置 `workspace-write` 或 `danger-full-access`,从而使沙箱形同虚设。而模型可见的旋钮(沙箱模式、批准策略)在 agent 生命周期内会变化——ACP 用户切换按会话设置、运维人员在进程停止期间编辑 `cordis.yml`——模型绝不能基于过时的信念行动:每次请求时的实际状态是什么、agent 存活期间发生了什么变化、无人看管时又发生了什么变化,都需要有明确答案。 @@ -50,11 +50,11 @@ OS 子进程约束适用于 bash 执行器(包括钩子命令),后续还 #### seam:`ctx.sandbox` -`dsh-sandbox` 拥有词汇和 `SandboxProvider` 契约:`confine(argv, policy)` 返回调用方应当 spawn 的替代 argv(经过包装,使进程及其所有子进程在约束下运行),加上所选后端达到的 `enforcement` 完整度、其拒绝方言(`denialSignatures`,该后端内核在拒绝文件操作时打印到 stderr 的子串)、以及其 runner 失败方言(`runnerFailureSignatures`,runner **本身**失败——因而命令从未运行——时的自我标识方式);没有可用后端时抛出失败关闭的 `SANDBOX_UNAVAILABLE` 错误,绝不静默放行。词汇:`SandboxMode`(`read-only` / `workspace-write` / `danger-full-access`,仅限文件操作——不声称覆盖网络和进程可见性)、`SandboxEnforcement`(`full` / `partial`)、`SandboxPolicy`(mode + workspace root)。 +`dsh-sandbox` 拥有词汇和 `SandboxProvider` 契约:`confine(argv, policy)` 返回调用方应当 spawn 的替代 argv(经过包装,使进程及其所有子进程在约束下运行),加上所选后端达到的 `enforcement` 完整度、其拒绝方言(`denialSignatures`,该后端内核在拒绝文件操作时打印到 stderr 的子串)、以及其 runner 失败方言(`runnerFailureSignatures`,runner 本身失败——因而命令从未运行——时的自我标识方式);没有可用后端时抛出失败关闭的 `SANDBOX_UNAVAILABLE` 错误,绝不静默放行。词汇:`SandboxMode`(`read-only` / `workspace-write` / `danger-full-access`,仅限文件操作——不声称覆盖网络和进程可见性)、`SandboxEnforcement`(`full` / `partial`)、`SandboxPolicy`(mode + workspace root)。 -策略随每次**调用**而非提供方携带:两个消费方可以在同一时刻以不同策略约束(bash 在 `read-only` 下运行,而一个受约束的子 agent 保持其状态目录可写),且经批准的升级重试是一次带有更宽策略的新调用——在配置固定的提供方模式下无法表达。 +策略随每次调用而非提供方携带:两个消费方可以在同一时刻以不同策略约束(bash 在 `read-only` 下运行,而一个受约束的子 agent 保持其状态目录可写),且经批准的升级重试是一次带有更宽策略的新调用——在配置固定的提供方模式下无法表达。 -该 seam 仅约束**同世界**子进程:后端共享主机的文件系统和内核。容器、microVM 和远程执行器不是此 seam 的后端——它们以环境一致的组替换整个能力实现(`ctx.bash`、`ctx.fs`),因为一个 bash 在容器中运行而 fs 工具写主机的 agent 生活在两个割裂的世界中。 +该 seam 仅约束同世界子进程:后端共享主机的文件系统和内核。容器、microVM 和远程执行器不是此 seam 的后端——它们以环境一致的组替换整个能力实现(`ctx.bash`、`ctx.fs`),因为一个 bash 在容器中运行而 fs 工具写主机的 agent 生活在两个割裂的世界中。 留待需要时再决定:网络限制是作为独立的 `network_mode` 到来,还是在某个 runner 同时强制两者后合并进 `sandbox_mode`;以及 `SandboxPolicy` 是现在就增加额外的可写根授权(launcher 已支持 `--rw `),还是等到升级机制需要时再加。 @@ -80,7 +80,7 @@ FIXME: Revisit the separate-repository boundary and try to maintain the launcher `BashExecRequest.sandboxMode` 是可选的按调用输入;解析后的 spec 使该字段显式。`BashExecutor.sandboxMode` 公布已挂载的执行器能否兑现它,因此只有约束组合才暴露升级。seam 接受任何显式模式;工具拥有「仅更宽」的升级规则。非沙箱执行器诚实地保持无约束。 -`SandboxBashExecutor.resolve()` 盖章有效模式——升级授权 > 会话覆盖 > 配置默认——使 `run()`/`start()` 读取 spec 而非配置。`danger-full-access` 分支、confine 调用和结果事实都以 spec 的模式为键,且按任务的事实 map 携带每个任务的模式及其包装事实(`notifyTaskDone()` 从 map 条目盖章):一次升级调用——前台或后台——报告它**实际**运行的模式,而每个邻居保持自己的。 +`SandboxBashExecutor.resolve()` 盖章有效模式——升级授权 > 会话覆盖 > 配置默认——使 `run()`/`start()` 读取 spec 而非配置。`danger-full-access` 分支、confine 调用和结果事实都以 spec 的模式为键,且按任务的事实 map 携带每个任务的模式及其包装事实(`notifyTaskDone()` 从 map 条目盖章):一次升级调用——前台或后台——报告它实际运行的模式,而每个邻居保持自己的。 当约束执行器被挂载时,`bash` 公布配对的 `sandbox_permissions` 和 `justification` 字段。schema 暴露完整的封闭升级词汇,因为有效模式是按会话的;执行拒绝任何不严格宽于该调用有效模式的目标。批准在执行之前解析。`allowed-once` 仅将授权模式盖章到该请求上,而 `rejected`、`cancelled`、`unavailable`、缺失的 approval 服务或缺失的 agent 都以各自不同的结果文本失败关闭。授权不持久化。 @@ -94,7 +94,7 @@ FIXME: Revisit the separate-repository boundary and try to maintain the launcher effective(session) = findLast(the session's own knob events)?.value ?? the composition-config default ``` -默认值是组合配置(`cordis.yml`)——运维人员拥有,进程范围。运行时切换是**会话范围**的覆盖,记录为该会话自身日志中的一条仅日志事件。重启免疫(恢复会话时回放其日志,覆盖自然恢复,无需追赶机制)和多会话隔离(一个编辑器标签页的 `workspace-write` 不会干扰另一个的 `read-only`)都是构造性的自然结果,且不存在任何外部配置存储。 +默认值是组合配置(`cordis.yml`)——运维人员拥有,进程范围。运行时切换是会话范围的覆盖,记录为该会话自身日志中的一条仅日志事件。重启免疫(恢复会话时回放其日志,覆盖自然恢复,无需追赶机制)和多会话隔离(一个编辑器标签页的 `workspace-write` 不会干扰另一个的 `read-only`)都是构造性的自然结果,且不存在任何外部配置存储。 **每个旋钮一种事件,由其领域拥有**——这是每个既有事件族已遵循的可合并扩展 `SessionEventMap` 惯用法(`dsh-user-approval` 中的 `approval/*`、hooks 包中的 `hook/*`): @@ -105,13 +105,13 @@ interface SessionEventMap { } ``` -每个拥有者导出相同的三件套:事件声明、纯 fold(`effectiveSandboxMode(events)` / `effectiveApprovalPolicy(events)`——一个 `findLast`,类型化到领域的封闭联合),以及**唯一的**写入路径(`setSandboxMode(session, mode)` / `setApprovalPolicy(session, policy)`——切换即其事件;没有任何东西在带外修改状态)。无共享拥有者服务、无通用 facts map、无注册表:第三个旋钮只需将约 40 行模式复制到自己的包中。执行在两侧都遵循 fold——bash 工具的按调用盖章将其作为 § 升级机制优先级链的中间层读取,approval seam 的 `'never'` 门控是[批准 RFC](2026-07-06-approval-seam.md) 同一模式的另一侧。 +每个拥有者导出相同的三件套:事件声明、纯 fold(`effectiveSandboxMode(events)` / `effectiveApprovalPolicy(events)`——一个 `findLast`,类型化到领域的封闭联合),以及唯一的写入路径(`setSandboxMode(session, mode)` / `setApprovalPolicy(session, policy)`——切换即其事件;没有任何东西在带外修改状态)。无共享拥有者服务、无通用 facts map、无注册表:第三个旋钮只需将约 40 行模式复制到自己的包中。执行在两侧都遵循 fold——bash 工具的按调用盖章将其作为 § 升级机制优先级链的中间层读取,approval seam 的 `'never'` 门控是[批准 RFC](2026-07-06-approval-seam.md) 同一模式的另一侧。 沙箱模式不在提示词中叙述;拒绝结果在需要时报告模式,避免基于常驻标签的预防性拒绝。批准策略不同:只有 `'never'` 被声明,因为自动拒绝在行为上与用户的「不」无法区分。策略变更通知被合并,由下一个 pre-step 递送,重启后有基于日志的回退。通知来源从事件位置推断:最后一个 request header 之后的旋钮事件是用户驱动的;未记录的漂移是运维人员或配置驱动的。 **编辑器界面**是协议原生的 [Session Config Options](https://agentclientprotocol.com/protocol/session-config-options)——该规范对 session modes 的替代(计划在 ACP v2 中移除),已有 SDK 类型。当 `ctx.permission` 被组合时,bridge 在 `session/new` 和 `session/load` 中公布一个 `permission` 选择器(category `mode`);其选项是部署的 preset 表,其 `currentValue` 是 `PermissionService.current()` 对会话日志加组合默认值的结果。随附的 `workspace-write` 和 `danger-full-access` preset 各自捆绑一个沙箱模式与一个批准策略,并写入两个领域 setter;preset 表之外的旋钮组合报告为仅可切换离开的 `custom`。`session/set_config_option` 通过 permission 服务验证并切换,然后返回完整的刷新状态(规范契约)。 -**轮次封闭是提交边界。**开放轮次中的切换立即追加。空闲切换保持在 bridge 记录上待定,在下一次 prompt 提交时、assembly 或执行之前追加到开放轮次中;每个旋钮以最后写入为准。开放性来自日志边界而非 `agent.status`,setter 不从 `session/event` 监听器内追加,因为那会重排后续观察者。锚定之前,响应叠加待定值。崩溃丢弃它,重新加载返回持久 fold。 +**轮次封闭是提交边界。** 开放轮次中的切换立即追加。空闲切换保持在 bridge 记录上待定,在下一次 prompt 提交时、assembly 或执行之前追加到开放轮次中;每个旋钮以最后写入为准。开放性来自日志边界而非 `agent.status`,setter 不从 `session/event` 监听器内追加,因为那会重排后续观察者。锚定之前,响应叠加待定值。崩溃丢弃它,重新加载返回持久 fold。 #### 进程内工具 @@ -121,10 +121,10 @@ FIXME: Revisit this tool-local boundary. The follow-up design needs to determine ### 测试 -- **单元测试:**固定平台选择和 profile、失败关闭的 runner 分类、按调用事实、升级验证和结果、permission preset fold 和写入透传、叙述器合并、ACP 公布和验证、轮次封闭的配置写入。 -- **Keyless 真实 runner:**在提供方和 bash 消费方层面对 bwrap、Landlock 和 Seatbelt 执行真实文件系统效果测试;packed-install 覆盖率证明注册表 launcher 保持可执行。真实 ACP 组合固定 permission 切换并拒绝未知 preset。CI 拒绝静默全跳过。 -- **With-key:**驱动真实模型、runner、bridge 应答器和磁盘效果通过授权和拒绝的升级;不可用的凭证或 runner 自动跳过。 -- **快照:**固定 permission config-option 协议格式(wire format)、preset 和旋钮事件、prompt delta 和通知、以及两个脚本化的 approval 分支。快照模式以无约束启动,使无关 fixture(测试前置数据)保持平台无关;策略场景显式切换。真实拒绝 stderr 留在平台测试中,因为其方言是 runner 特定的。 +- **单元测试:** 固定平台选择和 profile、失败关闭的 runner 分类、按调用事实、升级验证和结果、permission preset fold 和写入透传、叙述器合并、ACP 公布和验证、轮次封闭的配置写入。 +- **Keyless 真实 runner:** 在提供方和 bash 消费方层面对 bwrap、Landlock 和 Seatbelt 执行真实文件系统效果测试;packed-install 覆盖率证明注册表 launcher 保持可执行。真实 ACP 组合固定 permission 切换并拒绝未知 preset。CI 拒绝静默全跳过。 +- **With-key:** 驱动真实模型、runner、bridge 应答器和磁盘效果通过授权和拒绝的升级;不可用的凭证或 runner 自动跳过。 +- **快照:** 固定 permission config-option 协议格式(wire format)、preset 和旋钮事件、prompt delta 和通知、以及两个脚本化的 approval 分支。快照模式以无约束启动,使无关 fixture(测试前置数据)保持平台无关;策略场景显式切换。真实拒绝 stderr 留在平台测试中,因为其方言是 runner 特定的。 ## 延迟阶段 @@ -149,22 +149,22 @@ FIXME: Revisit this tool-local boundary. The follow-up design needs to determine - **一个接口同时覆盖容器/VM**:否决。`confine(argv)` 预设共享文件系统;环境隔离是作为一致组部署的能力兄弟后端。 - **通用 ToolRuntime 包装任何工具**:否决。对进程内工具(闭包了 `ctx`)机械上不成立;声明式效果重写对 fs/web/todo 而言不合理。 - **在执行器内部(`dsh-bash-sandbox`)请求批准**:否决。没有可路由的 `agent`,没有可附加 prompt 的 `callId`;添加它们会让传输 seam 了解会话和 UI——工具层持有两者并拥有面向模型的词汇。 -- **同一工具调用内自动重试**:否决。日志无法重建的隐藏重入:一个 `tool/call` 会产生两次具有不同策略的执行——重试是一次**新的**带有自身参数和结果事实的已记录调用。 +- **同一工具调用内自动重试**:否决。日志无法重建的隐藏重入:一个 `tool/call` 会产生两次具有不同策略的执行——重试是一次新的带有自身参数和结果事实的已记录调用。 - **无条件公布升级字段**:否决。在 `dsh-bash-local` 下它们是死杠杆——公布 harness 无法兑现的选项会制造注定失败的授权;能力门控仅需注册时一次读取。 - **默认值相对的升级阶梯(仅公布比执行器注册时默认值更宽的模式)**:否决。按会话覆盖使默认值成为错误的基线——切换到比默认值更窄的会话恰恰失去它需要的杠杆,而在 `danger-full-access` 默认值下字段完全消失,同时一个被覆盖为 `read-only` 的会话仍处于约束中却没有升级路径。枚举固定封闭的目标词汇;严格放宽是针对会话有效模式的按调用执行检查。 - **按会话动态工具 schema**:否决。schema 设计上是注册表全局的(一套 assembly 词汇、固定 header 快照契约),按会话重新注册只能买到执行时严格放宽检查已保证的东西,代价是按会话的 schema 表面和每次切换的 header 变动。 - **将重试硬匹配到先前的拒绝**:否决。命令字符串同一性脆弱(引号、`workdir`、env 前缀、作为失败阶段重试的管道)——要么误拒诚实的重试,要么被轻易满足;真正的边界是人看到命令 + 理由。仅在 `allow_always` 授权存储需要机器可检查的范围时才重新考虑。 - **通用 `env/state` facts map 加拥有者服务**:否决。approval 和 sandbox 独立组合,因此任何一方的状态都不应拖入第三个包;单键 fold 各自是一个 `findLast`,拥有者服务自然消解;没有跨旋钮的不变式,因此原子多键补丁无收益。 - **通过 `agent/user-message` + 总线事件叙述**:否决。它预设了一个不存在的轮次入口 seam(真正的 seam 是 `agent/prompt-submit`),而 pre-step 的位置以一个监听器同时服务合并的轮次入口通知和轮中即时性约束。 -- **提示词中常驻声明沙箱模式(+ 切换叙述器)**:先交付后移除,基于实际证据:当每个请求中都有 `Bash commands run under the "read-only" file sandbox.` 时,模型拒绝**尝试**被拒绝后可升级的工作(首次手动会话中十二个轮次有五个以零工具调用结束),将沙箱变成了软锁定。拒绝标记在需要时命名模式,升级字段承载恢复路径;批准旋钮保留其声明,因为自动拒绝在行为上与人的「不」无法区分。 -- **用专门的簿记事件追踪「上次告知」**:否决。`request/header*` fold 已记录模型看到的确切 prompt;将封闭的候选句子解析回来替代了第二条簿记流——事件仅在它们**本身即为存储**时才需要。 +- **提示词中常驻声明沙箱模式(+ 切换叙述器)**:先交付后移除,基于实际证据:当每个请求中都有 `Bash commands run under the "read-only" file sandbox.` 时,模型拒绝尝试被拒绝后可升级的工作(首次手动会话中十二个轮次有五个以零工具调用结束),将沙箱变成了软锁定。拒绝标记在需要时命名模式,升级字段承载恢复路径;批准旋钮保留其声明,因为自动拒绝在行为上与人的「不」无法区分。 +- **用专门的簿记事件追踪「上次告知」**:否决。`request/header*` fold 已记录模型看到的确切 prompt;将封闭的候选句子解析回来替代了第二条簿记流——事件仅在它们本身即为存储时才需要。 - **ACP session modes 而非 config options**:否决。preset 已经是一个部署定义的 config-option 选择器,且 modes 计划在 ACP v2 中移除。 ## 后果 已交付并固定的内容——测试中的各层级分别保障: -- 被拒绝的命令以 `sandbox_permissions` + `justification` 重试时,通过组合的应答器链提示用户;授权使**该次**调用在更宽模式下运行(结果事实如此报告),而其他所有调用保持各自的有效模式;每种非授权结果产生各自不同的错误文本且不执行任何内容。 +- 被拒绝的命令以 `sandbox_permissions` + `justification` 重试时,通过组合的应答器链提示用户;授权使该次调用在更宽模式下运行(结果事实如此报告),而其他所有调用保持各自的有效模式;每种非授权结果产生各自不同的错误文本且不执行任何内容。 - 升级字段恰好在已挂载的执行器约束时存在;不严格宽于调用有效模式的请求以自身文本失败关闭且不提示任何人;没有 ApprovalService 的部署对升级调用失败关闭,对普通调用不影响。 - 系统提示词从不声明沙箱模式(批准 `'never'` 策略是唯一被声明的旋钮),且整个交互——header、旋钮事件、通知、批准、结果——仅从会话日志即可重建,除两个旋钮事件外无额外事件类型。 - N 次空闲切换每个旋钮最多产生一个锚定事件(净零序列不锚定任何事件——客户端回显当前选择的无操作推送不记录任何内容);批准策略切换最多以一条合并通知叙述;轮中沙箱切换由下一次调用的盖章兑现。 @@ -175,31 +175,31 @@ FIXME: Revisit this tool-local boundary. The follow-up design needs to determine 代价与已接受的限制: - **单一包装的幻觉被有意放弃。**`tools/pre-execute` 包装加 prompt 约定无法解决沙箱批准——正确的设计需要结构化拒绝、原生 runner 探测、按调用策略承载和一致的跨工具族强制,本设计为此付出了代价。 -- **`read-only` 尚不是跨工具族边界。**在 fs 意图门控按共享模式决策之前,该声明仅对 bash 成立;契约诚实地如此声明(§ 进程内工具)。 -- **Windows 没有后端。**其链槽保留为空——失败关闭,绝不穿透;填充它是延迟阶段。 -- **Seatbelt 层级依赖 Apple 已弃用但仍交付的 `sandbox-exec` CLI。**作为 darwin 的唯一候选,它无需探测即被选中,因此未来移除会在执行时作为 runner 失败分类浮现——重新抛出 `SANDBOX_UNAVAILABLE`,命令从未运行;失败关闭,绝不开放。 -- **Landlock 约束的完整度取决于运行内核的 ABI。**报告为 `enforcement: 'partial'` 而非拒绝——这是有意的权衡,使备选在旧内核主机上仍可用。 -- **launcher 作为注册表依赖到达。**通过其自身仓库的发布流水线(经审查的 C 源码、原生 CI 构建器、字节固定的发布演练)加上本仓库的版本固定获得信任——真实内核 e2e 测试腿是通过安装字节为行为背书的。 -- **模型可能过度请求。**在没有拒绝依据的情况下升级,或在 `workspace-write` 足够时选择 `danger-full-access`:描述引导且枚举强制阶梯,但人的 prompt 是实际门控;`approval/asked` 原因使过度请求可审计,且 `prepend` 策略应答器可以自动拒绝部署永远不想要的模式。 +- **`read-only` 尚不是跨工具族边界。** 在 fs 意图门控按共享模式决策之前,该声明仅对 bash 成立;契约诚实地如此声明(§ 进程内工具)。 +- **Windows 没有后端。** 其链槽保留为空——失败关闭,绝不穿透;填充它是延迟阶段。 +- **Seatbelt 层级依赖 Apple 已弃用但仍交付的 `sandbox-exec` CLI。** 作为 darwin 的唯一候选,它无需探测即被选中,因此未来移除会在执行时作为 runner 失败分类浮现——重新抛出 `SANDBOX_UNAVAILABLE`,命令从未运行;失败关闭,绝不开放。 +- **Landlock 约束的完整度取决于运行内核的 ABI。** 报告为 `enforcement: 'partial'` 而非拒绝——这是有意的权衡,使备选在旧内核主机上仍可用。 +- **launcher 作为注册表依赖到达。** 通过其自身仓库的发布流水线(经审查的 C 源码、原生 CI 构建器、字节固定的发布演练)加上本仓库的版本固定获得信任——真实内核 e2e 测试腿是通过安装字节为行为背书的。 +- **模型可能过度请求。** 在没有拒绝依据的情况下升级,或在 `workspace-write` 足够时选择 `danger-full-access`:描述引导且枚举强制阶梯,但人的 prompt 是实际门控;`approval/asked` 原因使过度请求可审计,且 `prepend` 策略应答器可以自动拒绝部署永远不想要的模式。 - **公布的目标集是静态的,而有效模式是按会话的**(schema 是注册表全局的)——已处于最宽模式的会话仍被提供这些字段。构造上无害:执行时的严格放宽检查(而非枚举)是安全边界——非放宽请求以自身文本失败且不提示任何人。 -- **授权的升级不等于可工作的沙箱。**不可用的后端即使对授权升级到约束模式也仍然失败关闭——在平台没有链或所有探测失败时于 `confine()` 阶段,在未探测的唯一 runner 拒绝时于执行阶段(归类为沙箱失败而非命令失败)——而授权的 `danger-full-access` 运行根本不触及提供方:此时授权(而非探测)是权威。 -- **空闲切换存在于 bridge 内存中,直到下一次 prompt 提交锚定它。**该窗口内的崩溃将其回退(在 `session/load` 时报告),且永不再提交 prompt 的会话永不持久化它——已接受,loop 拥有的空闲提交轮次留作未来工作(如果持久性成为需求)。 -- **批准叙述器的重启基线解析 prompt 文本。**封闭的候选句子由写入模块本身拥有,因此措辞变更是同一文件中写入器+解析器的协调编辑;header 早于该段落的会话静默采用当前策略而不发通知。 +- **授权的升级不等于可工作的沙箱。** 不可用的后端即使对授权升级到约束模式也仍然失败关闭——在平台没有链或所有探测失败时于 `confine()` 阶段,在未探测的唯一 runner 拒绝时于执行阶段(归类为沙箱失败而非命令失败)——而授权的 `danger-full-access` 运行根本不触及提供方:此时授权(而非探测)是权威。 +- **空闲切换存在于 bridge 内存中,直到下一次 prompt 提交锚定它。** 该窗口内的崩溃将其回退(在 `session/load` 时报告),且永不再提交 prompt 的会话永不持久化它——已接受,loop 拥有的空闲提交轮次留作未来工作(如果持久性成为需求)。 +- **批准叙述器的重启基线解析 prompt 文本。** 封闭的候选句子由写入模块本身拥有,因此措辞变更是同一文件中写入器+解析器的协调编辑;header 早于该段落的会话静默采用当前策略而不发通知。 - **批准段落仍是动态 prompt 表面**(`'never'` 切换会破坏该会话的提供方 prompt 前缀缓存)。已接受:策略切换罕见,且模型基于过时的 `'never'` 行动更糟。沙箱旋钮不再触及 prompt。 - **模型可能持有关于沙箱模式的过时信念**(没有任何东西宣布切换)。有意接受:下一次尝试的标记或成功会纠正它,而宣布的观察到的失败模式——预防性拒绝——比一次浪费的重试更糟。 ## FAQ -- **一个命令返回了 `[sandbox: file access denied under read-only mode]`——它失败了吗?**它**运行了**,内核拒绝了一个文件操作:拒绝是与退出码正交的结果事实。教学禁止绕过它重试;唯一被认可的动作是以升级请求重试同一命令一次。 -- **如何区分损坏的沙箱与失败的命令?**Runner 失败在分类中优先于拒绝:匹配包装的 `runnerFailureSignatures` 的失败运行意味着命令**从未运行**——前台重新抛出结构化的 `SANDBOX_UNAVAILABLE` 并附带 runner 的 stderr 行,后台任务盖章 `sandbox.runnerFailed` 并渲染自己的标记。损坏的沙箱永远不会被读作失败的命令,且命令永远不会无约束运行。 -- **在没有后端的平台上会发生什么——今天的 Windows?**`confine()` 抛出失败关闭的 `SANDBOX_UNAVAILABLE`,命令永不 spawn;`win32` 是保留的**空**链,由测试固定为同样失败关闭,直到 Windows runner 填充它(§ 延迟阶段)。 -- **`bwrap` 已安装在我的主机上但不可用(禁用了非特权 userns、LSM 拒绝 `mount`)——会发生什么?**链探测是功能性的——它构建并强制一个真实 profile 而非检查 `--version`——因此存在但不可用的 `bwrap` 探测失败,选择落到注册表安装的 Landlock launcher,结论在提供方生命周期内缓存。 -- **沙箱限制网络或进程可见性吗?**不——`SandboxMode` 仅声称文件操作;bwrap profile 刻意不 unshare pid,没有后端声称网络。网络限制是否成为自己的旋钮留在 § seam 中开放。 -- **哪些工具实际在约束下运行?**通过 `ctx.bash` 的 OS 子进程——bash 工具,以及传递性的钩子命令。fs/web/todo 在进程内执行,`execve` 包装对它们机械上毫无意义;它们的 `read-only` 语义随跨工具族延迟阶段到来,在此之前契约诚实地声明仅限 bash。 -- **授权的升级会持久化吗?或覆盖后台任务吗?**都不会:授权被请求它的那次调用(前台或后台)消耗,该次调用报告它实际运行的模式,而每个邻居保持自己的。如何为通过 `bash_output` 延迟浮现的后台拒绝**定义**升级,留在 § 升级机制中开放。 -- **编辑器的模式切换何时生效?**轮中:立即追加,由下一次调用的盖章兑现。空闲:保持在 bridge 的会话记录上,在下一次 `agent/prompt-submit` 时锚定到其开放轮次中,N 次切换合并为最多一个事件(净零则无);锚定前崩溃回退它,`session/load` 报告真实状态。模型不被告知——其下一个命令直接在新模式下运行。 -- **重启后什么存活——如果运维人员在进程停止期间改了配置默认值呢?**覆盖从会话日志回放(`effective = fold ?? config`),因此恢复的会话以零追赶机制保持其模式;离线漂移的默认值以与切换相同的方式改变行为(批准策略因被声明,还额外以运维人员/配置归因叙述)。 -- **结果上的 `enforcement: 'partial'` 是什么意思?**所选后端强制其内核 ABI 管控的子集——例如 ABI v3 之前的 Landlock 不管控路径 truncate——并以结构化方式如此声明而非拒绝主机;探测的报告行区分各种情况。bwrap 和 Seatbelt profile 构造上管控所有承诺的文件操作,因此始终报告 `full`。 +- **一个命令返回了 `[sandbox: file access denied under read-only mode]`——它失败了吗?** 它运行了,内核拒绝了一个文件操作:拒绝是与退出码正交的结果事实。教学禁止绕过它重试;唯一被认可的动作是以升级请求重试同一命令一次。 +- **如何区分损坏的沙箱与失败的命令?** Runner 失败在分类中优先于拒绝:匹配包装的 `runnerFailureSignatures` 的失败运行意味着命令从未运行——前台重新抛出结构化的 `SANDBOX_UNAVAILABLE` 并附带 runner 的 stderr 行,后台任务盖章 `sandbox.runnerFailed` 并渲染自己的标记。损坏的沙箱永远不会被读作失败的命令,且命令永远不会无约束运行。 +- **在没有后端的平台上会发生什么——今天的 Windows?** `confine()` 抛出失败关闭的 `SANDBOX_UNAVAILABLE`,命令永不 spawn;`win32` 是保留的空链,由测试固定为同样失败关闭,直到 Windows runner 填充它(§ 延迟阶段)。 +- **`bwrap` 已安装在我的主机上但不可用(禁用了非特权 userns、LSM 拒绝 `mount`)——会发生什么?** 链探测是功能性的——它构建并强制一个真实 profile 而非检查 `--version`——因此存在但不可用的 `bwrap` 探测失败,选择落到注册表安装的 Landlock launcher,结论在提供方生命周期内缓存。 +- **沙箱限制网络或进程可见性吗?** 不——`SandboxMode` 仅声称文件操作;bwrap profile 刻意不 unshare pid,没有后端声称网络。网络限制是否成为自己的旋钮留在 § seam 中开放。 +- **哪些工具实际在约束下运行?** 通过 `ctx.bash` 的 OS 子进程——bash 工具,以及传递性的钩子命令。fs/web/todo 在进程内执行,`execve` 包装对它们机械上毫无意义;它们的 `read-only` 语义随跨工具族延迟阶段到来,在此之前契约诚实地声明仅限 bash。 +- **授权的升级会持久化吗?或覆盖后台任务吗?** 都不会:授权被请求它的那次调用(前台或后台)消耗,该次调用报告它实际运行的模式,而每个邻居保持自己的。如何为通过 `bash_output` 延迟浮现的后台拒绝定义升级,留在 § 升级机制中开放。 +- **编辑器的模式切换何时生效?** 轮中:立即追加,由下一次调用的盖章兑现。空闲:保持在 bridge 的会话记录上,在下一次 `agent/prompt-submit` 时锚定到其开放轮次中,N 次切换合并为最多一个事件(净零则无);锚定前崩溃回退它,`session/load` 报告真实状态。模型不被告知——其下一个命令直接在新模式下运行。 +- **重启后什么存活——如果运维人员在进程停止期间改了配置默认值呢?** 覆盖从会话日志回放(`effective = fold ?? config`),因此恢复的会话以零追赶机制保持其模式;离线漂移的默认值以与切换相同的方式改变行为(批准策略因被声明,还额外以运维人员/配置归因叙述)。 +- **结果上的 `enforcement: 'partial'` 是什么意思?** 所选后端强制其内核 ABI 管控的子集——例如 ABI v3 之前的 Landlock 不管控路径 truncate——并以结构化方式如此声明而非拒绝主机;探测的报告行区分各种情况。bwrap 和 Seatbelt profile 构造上管控所有承诺的文件操作,因此始终报告 `full`。 ## 先例 diff --git a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml index 03a68c9166..360ea648dc 100644 --- a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-07-mcp-client-plugin.md: 7706190257b54730532e4aa46cc9c47453c59871 -2026-07-07-mcp-client-plugin.zh.md: b5fee7eff7f12de5658f0a10c32cfeed71482fdf +2026-07-07-mcp-client-plugin.md: 99159d6ac31fb8ef74b28a7048392d0e22124b5a +2026-07-07-mcp-client-plugin.zh.md: e4c61f173956a928c4030fc53796324b924f32d9 diff --git a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.md b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.md index 7706190257..99159d6ac3 100644 --- a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.md +++ b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.md @@ -1,9 +1,9 @@ # RFC: MCP client plugin — connect to external MCP servers and bridge their tools -English | [中文](2026-07-07-mcp-client-plugin.zh.md) - Status: implemented +English | [中文](2026-07-07-mcp-client-plugin.zh.md) + ## Problem The harness had no way to consume tools from the MCP (Model Context Protocol) ecosystem. MCP is the emerging standard for tool servers — GitHub, filesystem, databases, code search, and hundreds of community servers expose tools via MCP. Users want to point the harness at one or more MCP servers and have their tools appear as native model-facing tools, without writing per-server glue code. diff --git a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.zh.md b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.zh.md index b5fee7eff7..e4c61f1739 100644 --- a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.zh.md +++ b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.zh.md @@ -1,4 +1,4 @@ -# RFC:MCP 客户端插件——连接外部 MCP 服务器并桥接其工具 +# RFC: MCP 客户端插件——连接外部 MCP 服务器并桥接其工具 Status: implemented @@ -54,7 +54,7 @@ interface StreamableHttpConfig { type Config = StdioConfig | StreamableHttpConfig ``` -`serverName` 是稳定的本地标识,用于在模型可见名称(见下文)中为该服务器的工具提供命名空间。它有意设计为用户配置,而**非**远端的 `serverInfo.name`:远端名称是不可信输入、跨部署不唯一(同一服务器的生产和预发布实例报告相同名称)、且可能在服务器升级时变化——这些都不得静默重命名模型可见工具。多个活跃实例使用重复的 `serverName` 属于配置错误:后加载的实例在启动时以可操作的错误消息失败,绝不静默覆盖或跳过。短 `serverName`(如 `gh`)也是缩短公开名称的调节手段。 +`serverName` 是稳定的本地标识,用于在模型可见名称(见下文)中为该服务器的工具提供命名空间。它有意设计为用户配置,而非远端的 `serverInfo.name`:远端名称是不可信输入、跨部署不唯一(同一服务器的生产和预发布实例报告相同名称)、且可能在服务器升级时变化——这些都不得静默重命名模型可见工具。多个活跃实例使用重复的 `serverName` 属于配置错误:后加载的实例在启动时以可操作的错误消息失败,绝不静默覆盖或跳过。短 `serverName`(如 `gh`)也是缩短公开名称的调节手段。 `cordis.yml` 用法示例: diff --git a/docs/rfc/implemented/feature/2026-07-07-session-prefix.i18n.yaml b/docs/rfc/implemented/feature/2026-07-07-session-prefix.i18n.yaml index 038349fd78..02d6f23514 100644 --- a/docs/rfc/implemented/feature/2026-07-07-session-prefix.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-07-session-prefix.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-07-session-prefix.md: ffa0fecb86e84ed64d45b24e1b6943d421757fb2 -2026-07-07-session-prefix.zh.md: ca38ebf337e16f4f2368ca74e394fcc1031fbf1f +2026-07-07-session-prefix.md: 81868c5b0c17c03aa1ebad788c8604dd30d1ce17 +2026-07-07-session-prefix.zh.md: 7d93d8190ce51fcbdc1b67e20fbdb4f4ea8e14c8 diff --git a/docs/rfc/implemented/feature/2026-07-07-session-prefix.md b/docs/rfc/implemented/feature/2026-07-07-session-prefix.md index ffa0fecb86..81868c5b0c 100644 --- a/docs/rfc/implemented/feature/2026-07-07-session-prefix.md +++ b/docs/rfc/implemented/feature/2026-07-07-session-prefix.md @@ -1,9 +1,9 @@ # RFC: The session prefix — request-only messages in front of the derived history -English | [中文](2026-07-07-session-prefix.zh.md) - Status: implemented +English | [中文](2026-07-07-session-prefix.zh.md) + ## Problem A plugin often owns a session-stable opener the model must always see — a skills catalog, an AGENTS.md digest, a workspace baseline. Before this seam the harness offered two homes, and both are wrong for that content. The system prompt is one rendered string: message-shaped content (a user-role `` envelope, a multi-message primer) does not fit it, and providers weight conversation messages differently from system text. Durable history (`agent.inject()`, a `context/message` at session start) makes the opener permanent: every `deriveMessages()` consumer replays it, the compaction retention walk owns it, forks bake it in stale, and a resume cannot refresh it — a catalog captured at session birth outlives the world it described. diff --git a/docs/rfc/implemented/feature/2026-07-07-session-prefix.zh.md b/docs/rfc/implemented/feature/2026-07-07-session-prefix.zh.md index ca38ebf337..7d93d8190c 100644 --- a/docs/rfc/implemented/feature/2026-07-07-session-prefix.zh.md +++ b/docs/rfc/implemented/feature/2026-07-07-session-prefix.zh.md @@ -1,4 +1,4 @@ -# RFC:会话前缀——派生历史之前的仅请求消息 +# RFC: 会话前缀——派生历史之前的仅请求消息 Status: implemented @@ -12,15 +12,15 @@ Status: implemented ## 决策 -`agent/session-prefix` 是 agent 事件映射上的一个 waterfall(瀑布式事件)([`packages/core/agent/src/types.ts`](../../../../packages/core/agent/src/types.ts)):监听器接收一个冻结的空种子并返回扩展(规范的贡献方式是前置插入 `[mine, ...await next()]`,在协议格式上产生注册顺序)。agent loop(智能体循环)([`packages/core/agent-loop/src/loop.ts`](../../../../packages/core/agent-loop/src/loop.ts))在每个循环实例中触发一次,惰性地在实例首次 `agent/pre-step` 之前执行;组合后的列表被深拷贝、深冻结、缓存在实例上,并在该实例发出的每个请求中置于**整个**派生历史之前——紧接在提供方的 system 槽位之后([协议格式顺序](../../../core-data-structures/core.md#the-request-envelope-llmcallconfig-and-the-logged-header))。 +`agent/session-prefix` 是 agent 事件映射上的一个 waterfall(瀑布式事件)([`packages/core/agent/src/types.ts`](../../../../packages/core/agent/src/types.ts)):监听器接收一个冻结的空种子并返回扩展(规范的贡献方式是前置插入 `[mine, ...await next()]`,在协议格式上产生注册顺序)。agent loop(智能体循环)([`packages/core/agent-loop/src/loop.ts`](../../../../packages/core/agent-loop/src/loop.ts))在每个循环实例中触发一次,惰性地在实例首次 `agent/pre-step` 之前执行;组合后的列表被深拷贝、深冻结、缓存在实例上,并在该实例发出的每个请求中置于整个派生历史之前——紧接在提供方的 system 槽位之后([协议格式顺序](../../../core-data-structures/core.md#the-request-envelope-llmcallconfig-and-the-logged-header))。 三个属性承载了这一设计: -- **仅请求,记录在 header 中。** `deriveMessages()` 从不返回前缀;它唯一的持久记录是实例锚定的 `request/header` 快照上的 `EpochHeader.messagePrefix`——可重建请求 RFC 已为请求的非历史部分拥有的通道,因此不引入新的会话事件。开发不变式([dsh-invariants](../../../../packages/support/invariants/src/index.ts))对每个循环构建的请求重新计算 `messagePrefix + 边界派生`;未记录的前缀无法到达协议格式。 +- **仅请求,记录在 header 中。** `deriveMessages()` 从不返回前缀;它唯一的持久记录是实例锚定的 `request/header` 快照上的 `EpochHeader.messagePrefix`——可重建请求 RFC 已为请求的非历史部分拥有的通道,因此不引入新的会话事件。开发不变式([dsh-invariants](../../../../packages/support/invariants/src/index.ts))对每个循环构建的请求重新计算 `messagePrefix + boundary derivation`;未记录的前缀无法到达协议格式。 - **按实例冻结。** 复用是结构性的,而非靠纪律保证:缓存的产物在会话中途不可变,因此提供方的 prompt 缓存从构造上成立,前缀以每步零边际成本扩展了可缓存区域。进程重启或 `ctx.agents.resume()` 产生新实例:它重新组合,任何漂移都可追溯地落在 `'resume'` header 快照上。这就是本 seam 创建的路由规则:会话冻结的开场内容走前缀;会话中途变化的内容走仅追加历史通道(`agent.inject()`、`tools/post-execute` 决策的 `additionalContext`、prompt-submit 的 `additionalContext`——[拦截 seam RFC](2026-06-30-interception-seams.md)),每条都是一次性支付的持久 `context/message`,之后被前缀缓存覆盖。 - **在压力门禁之前组合。** 组合先于实例的首次 `agent/pre-step`,且 seam 将组合值透传:`agent/pre-step` 携带 `sessionPrefix` 参数,`CompactService.compactIfNeeded(agent, fullSystemPrompt, sessionPrefix, signal)` 将其计入 token 压力估算。如果改为让门禁读取上一个实例折叠后的前缀,则在 resume 或 fork 后的实例中(贡献者可能已增长),门禁会低估压力、跳过压缩,发出超窗口的首个请求。在首次 pre-step 之前组合并将活值透传给 seam,使估算在每一步都精确。被 cancel/dispose 中断的组合(中断落在 waterfall 内部)会被丢弃,永不缓存:感知中止的监听器的降级回退不会泄漏到后续请求中,下一轮次在活信号下重新组合。 -由于组合在边界快照之前运行,组合监听器的会话追加会加入**当前**请求的派生历史。压缩在结构上不可能触及前缀(或系统提示词):它重写的是表面节点,而 header 状态从不进入表面。 +由于组合在边界快照之前运行,组合监听器的会话追加会加入当前请求的派生历史。压缩在结构上不可能触及前缀(或系统提示词):它重写的是表面节点,而 header 状态从不进入表面。 ## 测试 @@ -32,7 +32,7 @@ Status: implemented - **系统提示词分段**(`system-prompt/assemble`):对此类内容否决。assembly 渲染为单一 `system` 字符串,消息形态的开场放不进去;且系统提示词被设计为每步重新组装(变化时带 header delta),而开场内容需要按实例冻结的语义。 - **持久化历史开场**(会话启动时 `inject()`):否决。永久历史正是问题陈述中的失败模式——到处被回放、可被压缩、跨 resume 陈旧。 - **按轮次组合而非按实例组合**:否决。轮次边界的重新组合要么与日志静默失同步,要么强制每次变化都产生 header delta;且它每次触发都会破坏提供方缓存。合理的刷新点是实例边界,`'resume'` 快照已在那里可追溯地记录漂移。 -- **在首次请求时惰性组合,让压缩读取折叠后的 header**(最初合并时的形态):评审中被取代。折叠值仅从实例的第二个请求起才与活前缀匹配,因此在 resume/fork 后的实例首步,压力门禁读取的是**上一个**实例的前缀,可能低估压力。在首次 pre-step 之前组合并将活值透传给 seam,使估算在每一步都精确。 +- **在首次请求时惰性组合,让压缩读取折叠后的 header**(最初合并时的形态):评审中被取代。折叠值仅从实例的第二个请求起才与活前缀匹配,因此在 resume/fork 后的实例首步,压力门禁读取的是上一个实例的前缀,可能低估压力。在首次 pre-step 之前组合并将活值透传给 seam,使估算在每一步都精确。 - **专用会话事件承载前缀**:否决。header 事件按设计就是请求的非历史记录;第二个事件会为同一事实提供第二个归属,并多出一个需要保持完整的编解码器。 ## 后果 diff --git a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml index 5c62772145..0daf9b2490 100644 --- a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-08-repeat-tool-guard.md: 04d5d077a42b54ca7dc04a1efc9ea2f4034b642b -2026-07-08-repeat-tool-guard.zh.md: 917d958ca1019eb464b72b0201219de9dde7f658 +2026-07-08-repeat-tool-guard.md: e422ae70f61b6c77bf6517bc5eb840afc171d82c +2026-07-08-repeat-tool-guard.zh.md: eedb36f448bbca220e023a7609e1d9666fadb8e9 diff --git a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.md b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.md index 04d5d077a4..e422ae70f6 100644 --- a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.md +++ b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.md @@ -1,9 +1,9 @@ # RFC: Repeat-tool-call guard plugin -English | [中文](2026-07-08-repeat-tool-guard.zh.md) - Status: implemented +English | [中文](2026-07-08-repeat-tool-guard.zh.md) + ## Problem A model stuck in a loop re-issues the same tool call with byte-identical arguments — re-running a failing grep, re-reading an unchanged file, polling a command that already gave its answer — and each round trip burns tokens, wall-clock, and (for paid APIs) money without adding information. The harness has nothing that notices: the loop has no step budget, no plugin tracks call repetition, and the model only escapes when it happens to vary its own behavior. The failure mode is real and cheap to detect — [pi-repeat-tool-guard](https://github.com/Kingwl/pi-repeat-tool-guard) ships exactly this as a pi coding-agent extension: count consecutive identical calls and, past a threshold, append a `` telling the model to stop repeating itself and change course. diff --git a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.zh.md b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.zh.md index 917d958ca1..eedb36f448 100644 --- a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.zh.md +++ b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.zh.md @@ -1,4 +1,4 @@ -# RFC:重复工具调用守卫插件 +# RFC: 重复工具调用守卫插件 Status: implemented diff --git a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml index ba1e1f60be..45ea89f234 100644 --- a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-08-self-referential-cordis-toolset.md: 62b97dc4bdbd0e0b5b1f67f77c763065c79964ed -2026-07-08-self-referential-cordis-toolset.zh.md: 44648d7a3f195f2dc84121c0d014e5193484b106 +2026-07-08-self-referential-cordis-toolset.md: c79bc09dde85d79adc5435f3e08c702cab1369d9 +2026-07-08-self-referential-cordis-toolset.zh.md: e6cada0530652cfb40e7ea1edadf1b12e0f07e77 diff --git a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md index 62b97dc4bd..c79bc09dde 100644 --- a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md +++ b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md @@ -1,9 +1,9 @@ # RFC: The self-referential cordis toolset -English | [中文](2026-07-08-self-referential-cordis-toolset.zh.md) - Status: implemented +English | [中文](2026-07-08-self-referential-cordis-toolset.zh.md) + ## Problem Everything in this harness is a cordis plugin, but the agent running inside that plugin runtime cannot see or touch it: it cannot enumerate the services and events around it, cannot extend itself with a new tool mid-session, and cannot compose capabilities it invents. Handing the model that power is worth exploring — a self-referential agent that inspects and modifies its own runtime — but it raises three correctness problems at once, and the design is about answering them rather than the raw "let the model run code" mechanic. diff --git a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md index 44648d7a3f..e6cada0530 100644 --- a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md +++ b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md @@ -1,9 +1,9 @@ -# RFC:自引用 cordis 工具集 - -[English](2026-07-08-self-referential-cordis-toolset.md) | 中文 +# RFC: 自引用 cordis 工具集 Status: implemented +[English](2026-07-08-self-referential-cordis-toolset.md) | 中文 + ## 问题 本 harness 中的一切都是 cordis 插件,但运行在该插件运行时内部的 agent(智能体)既看不到也碰不到它:它无法枚举周围的服务和事件,无法在会话中途为自己添加新工具,也无法组合自己发明的能力。赋予模型这种能力值得探索——一个能审视并修改自身运行时的自引用 agent——但这同时引发三个正确性问题,本设计的核心正是回答这些问题,而非单纯的「让模型执行代码」机制。 diff --git a/docs/rfc/implemented/feature/2026-07-10-session-query-service.i18n.yaml b/docs/rfc/implemented/feature/2026-07-10-session-query-service.i18n.yaml index c824942f12..30fa8ab09e 100644 --- a/docs/rfc/implemented/feature/2026-07-10-session-query-service.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-10-session-query-service.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-10-session-query-service.md: 8b742ac19fea21d8404f5f44aa64f8c3cb3efccc -2026-07-10-session-query-service.zh.md: 73f47d0cc0306b3dcb6552c686f8f1a71ffbdc87 +2026-07-10-session-query-service.md: 8c990f4407d91c0be1fc01046e34aa3e76076ed4 +2026-07-10-session-query-service.zh.md: ea0d2d52668fb40b97621884f635cb03dea6f663 diff --git a/docs/rfc/implemented/feature/2026-07-10-session-query-service.md b/docs/rfc/implemented/feature/2026-07-10-session-query-service.md index 8b742ac19f..8c990f4407 100644 --- a/docs/rfc/implemented/feature/2026-07-10-session-query-service.md +++ b/docs/rfc/implemented/feature/2026-07-10-session-query-service.md @@ -1,9 +1,9 @@ # RFC: Exact session query service -English | [中文](2026-07-10-session-query-service.zh.md) - Status: implemented +English | [中文](2026-07-10-session-query-service.zh.md) + ## Problem Session history exists in two places: current `SessionStore` objects and an optional persistence backend. Consumers that need exact inspection would otherwise duplicate live-versus-persisted precedence, persistence lifecycle handling, raw-event surface classification, and defensive cloning. Durable state can lag the live log between checkpoints, so persistence alone is not a truthful current source. diff --git a/docs/rfc/implemented/feature/2026-07-10-session-query-service.zh.md b/docs/rfc/implemented/feature/2026-07-10-session-query-service.zh.md index 73f47d0cc0..ea0d2d5266 100644 --- a/docs/rfc/implemented/feature/2026-07-10-session-query-service.zh.md +++ b/docs/rfc/implemented/feature/2026-07-10-session-query-service.zh.md @@ -1,9 +1,9 @@ -# RFC:精确会话查询服务 - -[English](2026-07-10-session-query-service.md) | 中文 +# RFC: 精确会话查询服务 Status: implemented +[English](2026-07-10-session-query-service.md) | 中文 + ## 问题 会话历史存在于两处:当前的 `SessionStore` 对象与可选的持久化后端。需要精确检查的消费方若无统一服务,就不得不各自重复实现活跃/持久化优先级判定、持久化生命周期处理、原始事件的 surface 分类以及防御性克隆。在检查点之间,持久化状态可能落后于活跃日志,因此仅靠持久化并非当前状态的可靠来源。 diff --git a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml index 6675490bb9..65e180d55d 100644 --- a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-12-subagent-persona-tool-filter-and-depth.md: 368f3a3592c5e241bb9357d4d4ce32e175c3de45 -2026-07-12-subagent-persona-tool-filter-and-depth.zh.md: cc78a472df014ce1eb9114277e0520c7e9c051bb +2026-07-12-subagent-persona-tool-filter-and-depth.md: c88695d4444008bff69fcb10e3cf33c7b8820b9b +2026-07-12-subagent-persona-tool-filter-and-depth.zh.md: 1efbbce57274c11b2811ebe844c9cd80f81f407f diff --git a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md index 368f3a3592..c88695d444 100644 --- a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md +++ b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md @@ -1,9 +1,9 @@ # RFC: Configure subagent persona, tool visibility, and depth -English | [中文](2026-07-12-subagent-persona-tool-filter-and-depth.zh.md) - Status: implemented +English | [中文](2026-07-12-subagent-persona-tool-filter-and-depth.zh.md) + ## Problem A reusable subagent provider answers how to run a child, but different delegation tools need different child behavior. One deployment may want a reviewer persona, a research-only tool set, or a hard recursion bound without creating a new provider for every combination. diff --git a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md index cc78a472df..1efbbce572 100644 --- a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md +++ b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md @@ -1,9 +1,9 @@ -# RFC:配置 subagent 的人设、工具可见性与深度 - -[English](2026-07-12-subagent-persona-tool-filter-and-depth.md) | 中文 +# RFC: 配置 subagent 的人设、工具可见性与深度 Status: implemented +[English](2026-07-12-subagent-persona-tool-filter-and-depth.md) | 中文 + ## 问题 一个可复用的 subagent 提供方解决的是「如何运行子 agent(智能体)」的问题,但不同的委派工具需要不同的子 agent 行为。某个部署可能需要评审者人设、仅限研究的工具集,或硬性递归上限,而不必为每种组合创建新的提供方。 diff --git a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml index 120abae517..1e877bfba3 100644 --- a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-doc-sync-enforcement.md: 44ea84daddcae73ce07b0a8240f83ee9945e449d -2026-06-11-doc-sync-enforcement.zh.md: c739e9661bb926c772f1d5399529a813ac59991c +2026-06-11-doc-sync-enforcement.md: cb238291f9ff5ba5d6333cdf2fe75a43fe3e8eea +2026-06-11-doc-sync-enforcement.zh.md: a443cfcd6f9bd17ae1512683ff8cd82411fb8590 diff --git a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.md b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.md index 44ea84dadd..cb238291f9 100644 --- a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.md +++ b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.md @@ -1,9 +1,9 @@ # RFC: Doc-sync enforcement -English | [中文](2026-06-11-doc-sync-enforcement.zh.md) - Status: implemented +English | [中文](2026-06-11-doc-sync-enforcement.zh.md) + ## Problem AGENTS.md promises that docs and code stay strictly in sync, but the promise was verified by eyeball. Review caught drift twice — a cookbook example contradicting the type policy, and a README citing the wrong `registerAdapter` call. Out-of-sync docs are worse than no docs, and this codebase is built primarily by agents that follow gates far more reliably than prose (mechanical quality gates). Two classes of doc drift are mechanically checkable: code blocks that no longer compile, and the event-taxonomy table that duplicates the `interface Events` declarations. diff --git a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.zh.md b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.zh.md index c739e9661b..a443cfcd6f 100644 --- a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.zh.md +++ b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.zh.md @@ -1,9 +1,9 @@ -# RFC:Doc-sync 强制 - -[English](2026-06-11-doc-sync-enforcement.md) | 中文 +# RFC: Doc-sync 强制 Status: implemented +[English](2026-06-11-doc-sync-enforcement.md) | 中文 + ## 问题 AGENTS.md 承诺文档与代码严格同步,但这一承诺此前仅靠人眼核查。评审曾两次发现漂移:一次是实操手册(cookbook)示例与类型策略矛盾,一次是 README 引用了错误的 `registerAdapter` 调用。失去同步的文档比没有文档更糟;而本代码库主要由 agent(智能体)构建,agent 遵守门禁远比遵守行文约定可靠(机械质量门禁)。有两类文档漂移可以被机械检查:不再能编译的代码块,以及与 `interface Events` 声明重复的事件分类体系表。 @@ -15,7 +15,7 @@ AGENTS.md 承诺文档与代码严格同步,但这一承诺此前仅靠人眼 1. **`doc-typecheck`** 从 `README.md`、`docs/**` 和 `packages/*/README.md` 中提取所有 ` ```ts ` 围栏代码块,写入一个继承根 `tsconfig.json` 的临时项目,然后用 `tsc -b` 编译。临时项目复用源码的 `paths` 映射和根 project references,因此文档示例能看到源码,而 vendor 代码仍在其自身的 tsconfig 设置下被检查。刻意作为草图的代码块可通过显式的 ` ```ts ignore-check ` 信息字符串来 opt-out;脚本会报告 opt-out 比例,超过一半即失败,防止该豁免机制悄然成为常态。 2. **`verify-event-taxonomy`** 从 `packages/*/src` 中的 `interface Events` 块和 `docs/architecture.md` 中的分类体系表分别提取事件名称,断言两个集合完全一致。只校验,不生成:表格保留手写的 Mode/Purpose 列,仅检查名称集合。(落地此门禁时发现了表格遗漏的三个事件:`tools/change`、`llm/adapter-change`、`system-prompt/change`。)**已被取代**:由[生成式 Cordis 目录](2026-06-20-generated-cordis-catalog.md)取代。此门禁及其 `architecture.md` 表格已退役,取而代之的是完全生成的 `docs/cordis-catalog/events.md` + `docs/cordis-catalog/services.md` 及其 `verify-cordis-catalog` 新鲜度门禁。本 RFC 中的其他门禁(`doc-typecheck` 以及下文修订中的 `verify-md-wrap`)不受影响。 -两者通过一个共享的 doc-sync(文档同步门禁)`package.json` 脚本运行,lefthook pre-push 钩子和 CI 都调用它([机械质量门禁](2026-06-11-quality-gates.md):钩子与 CI 调用相同脚本,因此门禁在推送前就在本地触发,而非仅在推送后)。它们在 `pnpm run typecheck` 之后运行,后者校验 doc-typecheck 所引用的 package/vendor 构建图。 +两者通过一个共享的 `doc-sync`(文档同步门禁)package.json 脚本运行,lefthook pre-push 钩子和 CI 都调用它([机械质量门禁](2026-06-11-quality-gates.md):钩子与 CI 调用相同脚本,因此门禁在推送前就在本地触发,而非仅在推送后)。它们在 `pnpm run typecheck` 之后运行,后者校验 doc-typecheck 所引用的 package/vendor 构建图。 **修订(2026-06-17):** 第三道门禁 **`verify-md-wrap`** 随后被纳入 `doc-sync`。它使用 `mdast-util-from-markdown` + GFM 解析范围内的每个 Markdown 文件(`README.md`、`docs/**`、`packages/*/README.md`,加上 `AGENTS.md` / `packages/AGENTS.md`),如果任何 `paragraph` 节点跨越多个源码行则失败,从而强制执行 docs/AGENTS.md 中「一个段落一个物理行」的写作规则。同样遵循只校验不生成的原则:它报告硬换行但从不重写,因此不会引入格式化噪音。`doc-sync` 现在包含三道门禁。 diff --git a/docs/rfc/implemented/process/2026-06-11-quality-gates.i18n.yaml b/docs/rfc/implemented/process/2026-06-11-quality-gates.i18n.yaml index ba5bb828a2..be4c70583e 100644 --- a/docs/rfc/implemented/process/2026-06-11-quality-gates.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-11-quality-gates.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-quality-gates.md: 9862dc019dd6ff3b4639983821256395d0ee7b77 -2026-06-11-quality-gates.zh.md: a9c17bb700db091d21f7930942a8f3bbf55958a0 +2026-06-11-quality-gates.md: 2d6b6815e80a728cb61a86e9f7a488340fe06fc9 +2026-06-11-quality-gates.zh.md: f5088811f8562f5103740d39b48bd14c6d1da00c diff --git a/docs/rfc/implemented/process/2026-06-11-quality-gates.md b/docs/rfc/implemented/process/2026-06-11-quality-gates.md index 9862dc019d..2d6b6815e8 100644 --- a/docs/rfc/implemented/process/2026-06-11-quality-gates.md +++ b/docs/rfc/implemented/process/2026-06-11-quality-gates.md @@ -1,9 +1,9 @@ # RFC: Mechanical quality gates over prose guidelines -English | [中文](2026-06-11-quality-gates.zh.md) - Status: implemented +English | [中文](2026-06-11-quality-gates.zh.md) + ## Problem This codebase is developed primarily by coding agents. Agents follow enforced gates far more reliably than prose conventions, and "a lot of work" is not a cost argument when agents do the labor. Early evidence: tests that didn't typecheck shipped (vitest doesn't typecheck) and were only caught by a review. diff --git a/docs/rfc/implemented/process/2026-06-11-quality-gates.zh.md b/docs/rfc/implemented/process/2026-06-11-quality-gates.zh.md index a9c17bb700..f5088811f8 100644 --- a/docs/rfc/implemented/process/2026-06-11-quality-gates.zh.md +++ b/docs/rfc/implemented/process/2026-06-11-quality-gates.zh.md @@ -1,9 +1,9 @@ -# RFC:以机械质量门禁取代行文约定 - -[English](2026-06-11-quality-gates.md) | 中文 +# RFC: 以机械质量门禁取代行文约定 Status: implemented +[English](2026-06-11-quality-gates.md) | 中文 + ## 问题 本代码库主要由 coding agent(智能体)开发。相比行文约定,agent 遵守强制门禁的可靠性远高得多;而当劳动由 agent 承担时,「工作量大」不构成成本论据。早期证据:未通过类型检查的测试被提交(vitest 不做类型检查),仅在评审中才被发现。 @@ -15,7 +15,7 @@ AGENTS.md 中的每一条承诺都对应一个以非零退出码表示失败的 - 最严格的 TypeScript 配置(`noUncheckedIndexedAccess`、`exactOptionalPropertyTypes` 等);示例、测试和脚本通过根目录的 no-emit `tsconfig.json` 在 CI 中进行类型检查,而 package/vendor 代码保持在各自 project-reference 边界之后。 - ESLint strict-type-checked + @stylistic(作为强制执行的统一代码风格),包括文件内重复逻辑检查;vendor 代码排除在外。 - jscpd 检测 package 生产 TypeScript 与仓库脚本中的跨文件克隆;窄范围的源码区间例外用于记录有意为之的并行实现。 -- `packages/*/*/src` 下按文件 100% 覆盖率(v8);不可达的防御性守卫使用 `/* v8 ignore */` 并注明理由,而非删除。 +- `packages/*/*/src` 下按文件 100% 覆盖率(v8);不可达的防御性守卫使用 `/* v8 ignore */ ` 并注明理由,而非删除。 - knip(死代码/依赖)、publint(包(package)正确性)、workspace 约束(workspace 规则:private、cordis peer+dev、统一版本、ESM),以及对构建出的包声明文件进行 NodeNext 消费方类型检查。 - lefthook pre-commit(lint 暂存文件、类型检查、vendor manifest(元数据清单)守卫)和 pre-push(测试、hygiene);CI 在 Node 22.19/24/26 上运行完整矩阵,外加一个驱动 echo-agent 端到端的演示冒烟测试。 diff --git a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml index 92dd0f65b6..bb496d19e3 100644 --- a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-tsdown-over-dumble.md: c16ac691a9452d952303cf73b40693447d25015c -2026-06-11-tsdown-over-dumble.zh.md: 5e9dc5242225e4420e1faa6ef19c8e8b9b3fdbcd +2026-06-11-tsdown-over-dumble.md: b1ce354b9b2baa042d8aa1be2a8de171ed4adfef +2026-06-11-tsdown-over-dumble.zh.md: 4bdd9939901ef376f2f6ccded609b644a4698495 diff --git a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.md b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.md index c16ac691a9..b1ce354b9b 100644 --- a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.md +++ b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.md @@ -1,9 +1,9 @@ # RFC: tsdown for JS bundling instead of dumble -English | [中文](2026-06-11-tsdown-over-dumble.zh.md) - Status: implemented +English | [中文](2026-06-11-tsdown-over-dumble.zh.md) + ## Problem The initial build used **dumble**, the cordiverse zero-config esbuild wrapper that upstream Cordis itself builds with — maximum alignment with the vendored packages' conventions (it reads each package.json and infers entries/formats from the `exports` field). But dumble is a liability as a load-bearing tool in this repo: v0.2.x, ~530 npm downloads/week, effectively one maintainer, and we were invoking it through a custom orchestration script (`scripts/build.ts`) because it has no workspace mode. diff --git a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.zh.md b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.zh.md index 5e9dc52422..4bdd993990 100644 --- a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.zh.md +++ b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.zh.md @@ -1,9 +1,9 @@ -# RFC:使用 tsdown 替代 dumble 进行 JS 打包 - -[English](2026-06-11-tsdown-over-dumble.md) | 中文 +# RFC: 使用 tsdown 替代 dumble 进行 JS 打包 Status: implemented +[English](2026-06-11-tsdown-over-dumble.md) | 中文 + ## 问题 最初的构建使用 **dumble**,即 cordiverse 的零配置 esbuild 包装层——上游 Cordis 自身也用它构建——与 vendor 包(package)的约定最大程度对齐(它读取每个 package.json 并从 `exports` 字段推断入口/格式)。但 dumble 作为本仓库的承重工具存在隐患:v0.2.x,每周约 530 次 npm 下载,实质上只有一位维护者,而且由于它没有 workspace 模式,我们不得不通过自定义编排脚本(`scripts/build.ts`)来调用它。 diff --git a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml index b71b7d025d..339d733f07 100644 --- a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-vendor-cordis-as-source.md: 39506300dec73d0c9eb1b7b2246caa23f1b10f7f -2026-06-11-vendor-cordis-as-source.zh.md: 0e794d97c4d535b74279bab11bda519e7da2e366 +2026-06-11-vendor-cordis-as-source.md: 6e1af616785411a20496334fb35e0c7a3bc41b43 +2026-06-11-vendor-cordis-as-source.zh.md: bb9413fbba34e9a7040fd2e0a1bbcff1ba2345ff diff --git a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.md b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.md index 39506300de..6e1af61678 100644 --- a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.md +++ b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.md @@ -1,9 +1,9 @@ # RFC: Vendor Cordis as source, not npm dependencies -English | [中文](2026-06-11-vendor-cordis-as-source.zh.md) - Status: implemented +English | [中文](2026-06-11-vendor-cordis-as-source.zh.md) + ## Problem DeepSeek Harness SDK is built on the Cordis framework. Cordis core was at 4.0.0-rc.6 (a release candidate) when this repo started; the harness depends on framework internals (fiber lifecycle, effect disposal, waterfall dispatch) whose exact behavior matters to the agent loop's correctness guarantees. diff --git a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md index 0e794d97c4..bb9413fbba 100644 --- a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md +++ b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md @@ -1,9 +1,9 @@ -# RFC:将 Cordis 以源码形式收录,而非作为 npm 依赖 - -[English](2026-06-11-vendor-cordis-as-source.md) | 中文 +# RFC: 将 Cordis 以源码形式收录,而非作为 npm 依赖 Status: implemented +[English](2026-06-11-vendor-cordis-as-source.md) | 中文 + ## 问题 DeepSeek Harness SDK 构建于 Cordis 框架之上。本仓库启动时,Cordis core 处于 4.0.0-rc.6(一个候选发布版本);harness 依赖框架内部实现(fiber 生命周期、dispose(资源释放)、waterfall(瀑布式事件)分发),其确切行为直接关系到 agent loop(智能体循环)的正确性保证。 diff --git a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml index ec328ff0e0..41084092d0 100644 --- a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-16-pnpm-over-yarn.md: 6e7a6e1f53056e36f54f44b87b305afa593da549 -2026-06-16-pnpm-over-yarn.zh.md: ba63575909f2bafbbad2102c85d6bede77999997 +2026-06-16-pnpm-over-yarn.md: f5787dc3019f2c474761972afb11deb42f3950e0 +2026-06-16-pnpm-over-yarn.zh.md: 0f5acd13f6f113a569fbe4e7b92df62309c76537 diff --git a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.md b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.md index 6e7a6e1f53..f5787dc301 100644 --- a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.md +++ b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.md @@ -1,9 +1,9 @@ # RFC: pnpm as the package manager instead of Yarn 4 -English | [中文](2026-06-16-pnpm-over-yarn.zh.md) - Status: implemented +English | [中文](2026-06-16-pnpm-over-yarn.zh.md) + ## Problem The repo shipped on **Yarn 4** with the `node-modules` linker — a deliberately conservative choice that behaves like npm's flat layout while giving us Yarn's workspaces and `yarn constraints`. It worked. But Yarn 4's Plug'n'Play heritage makes the `node-modules` linker the off-the-beaten-path mode, and the broader JS ecosystem — tooling defaults, CI actions, Corepack examples, contributor familiarity — increasingly centers on pnpm. For a repo that is built primarily by agents and read by occasional human contributors, "the package manager most tools and people expect" has real value: fewer surprises, better-trodden failure paths, more copy-pasteable answers. diff --git a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.zh.md b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.zh.md index ba63575909..0f5acd13f6 100644 --- a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.zh.md +++ b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.zh.md @@ -1,9 +1,9 @@ -# RFC:使用 pnpm 替代 Yarn 4 作为包管理器 - -[English](2026-06-16-pnpm-over-yarn.md) | 中文 +# RFC: 使用 pnpm 替代 Yarn 4 作为包管理器 Status: implemented +[English](2026-06-16-pnpm-over-yarn.md) | 中文 + ## 问题 本仓库最初使用 **Yarn 4** 搭配 `node-modules` 链接器启动。这是一个刻意保守的选择:行为类似 npm 的扁平布局,同时享有 Yarn 的 workspaces 和 `yarn constraints`。它能正常工作。但 Yarn 4 源自 Plug'n'Play 的血统,使得 `node-modules` 链接器成为非主流模式;而更广泛的 JS 生态——工具默认值、CI action、Corepack 示例、贡献者的熟悉度——正日益以 pnpm 为中心。对于一个主要由 agent(智能体)构建、偶尔有人类贡献者阅读的仓库而言,「大多数工具和人所期望的包管理器」具有实际价值:更少的意外、更成熟的故障路径、更多可直接复用的解答。 diff --git a/docs/rfc/implemented/process/2026-06-17-ts-build-config.i18n.yaml b/docs/rfc/implemented/process/2026-06-17-ts-build-config.i18n.yaml index 92e8c81d4b..413c51c906 100644 --- a/docs/rfc/implemented/process/2026-06-17-ts-build-config.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-17-ts-build-config.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-17-ts-build-config.md: cf70014b5873f74da8476c21dd71feedb956f59f -2026-06-17-ts-build-config.zh.md: d3dd0fb13edd22f1ae365286cbf8144fa0bc3f69 +2026-06-17-ts-build-config.md: 9a75bcc3f043576f1cb793c38e0166aa0a010f68 +2026-06-17-ts-build-config.zh.md: c0f6bd40f3f0b06e79b9dc9f9c7812481413374c diff --git a/docs/rfc/implemented/process/2026-06-17-ts-build-config.md b/docs/rfc/implemented/process/2026-06-17-ts-build-config.md index cf70014b58..9a75bcc3f0 100644 --- a/docs/rfc/implemented/process/2026-06-17-ts-build-config.md +++ b/docs/rfc/implemented/process/2026-06-17-ts-build-config.md @@ -1,9 +1,9 @@ # RFC: TSC-first build and one tsconfig -English | [中文](2026-06-17-ts-build-config.zh.md) - Status: implemented +English | [中文](2026-06-17-ts-build-config.zh.md) + ## Problem The current TypeScript build and typecheck setup had these issues: diff --git a/docs/rfc/implemented/process/2026-06-17-ts-build-config.zh.md b/docs/rfc/implemented/process/2026-06-17-ts-build-config.zh.md index d3dd0fb13e..c0f6bd40f3 100644 --- a/docs/rfc/implemented/process/2026-06-17-ts-build-config.zh.md +++ b/docs/rfc/implemented/process/2026-06-17-ts-build-config.zh.md @@ -1,9 +1,9 @@ -# RFC:TSC 优先的构建与单一 tsconfig - -[English](2026-06-17-ts-build-config.md) | 中文 +# RFC: TSC 优先的构建与单一 tsconfig Status: implemented +[English](2026-06-17-ts-build-config.md) | 中文 + ## 问题 此前的 TypeScript 构建与类型检查配置存在以下问题: @@ -17,7 +17,7 @@ Status: implemented - `tsdown` 使用 `oxc` 进行 TypeScript 转换,其行为与 `tsc` 不同。 - `tsdown` 输出的打包 `.d.ts` 与 Cordis 内部的相对模块增强(module augmentation)结构冲突。 - - `tsc` 的输出受 `allowImportingTsExtensions` 影响,因此需要确保生成的 `.js` 文件不会导入 `.ts` 文件,且生成的 `.d.ts` 文件保留 NodeNext/Node16 接受的显式相对说明符。为此,包内相对导入在 TypeScript 源码中使用显式 `.ts` 说明符,由 `rewriteRelativeImportExtensions` 在输出的 JS 中将其重写为 `.js`。 + - tsc 的输出受 `allowImportingTsExtensions` 影响,因此需要确保生成的 `.js` 文件不会导入 `.ts` 文件,且生成的 `.d.ts` 文件保留 NodeNext/Node16 接受的显式相对说明符。为此,包内相对导入在 TypeScript 源码中使用显式 `.ts` 说明符,由 `rewriteRelativeImportExtensions` 在输出的 JS 中将其重写为 `.js`。 - `tsdown` 输出的打包 `.js` 与 `tsc -b` 逐文件输出的 `.js` 行为不同,例如装饰器转换行为。 - `vendor/*/src`、示例、测试和脚本无法全部以 plain-include 方式纳入一个根目录的严格程序。 - 在根目录严格配置下直接对 `vendor/*/src` 做类型检查,会触发大量不属于本项目所有权范围的类型错误。 diff --git a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml index 2b7b62f141..0f0677a911 100644 --- a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-18-markdown-cross-link-lint.md: c802b4071abf652824647e4417cde3f518776353 -2026-06-18-markdown-cross-link-lint.zh.md: 917580ffce71258896f3d23ef7efef4be0176949 +2026-06-18-markdown-cross-link-lint.md: f7ab6a4fd2b2c5cadaeabd5ef0c89f1097b5b44d +2026-06-18-markdown-cross-link-lint.zh.md: 61187042a3a0d3535479ffe3a796b6c1fdb82f5e diff --git a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.md b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.md index c802b4071a..f7ab6a4fd2 100644 --- a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.md +++ b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.md @@ -1,9 +1,9 @@ # RFC: Markdown cross-link validity linting -English | [中文](2026-06-18-markdown-cross-link-lint.zh.md) - Status: implemented +English | [中文](2026-06-18-markdown-cross-link-lint.zh.md) + ## Problem Docs in this repo link to each other by relative path — `[topic](../implemented/2026-…-….md)`, `[the cookbook](adding-a-tool.md)`, `[architecture.md](../../architecture.md)`. Nothing verified those targets exist. A rename or a move silently breaks every inbound link, and the break is invisible until a reader clicks it. [Doc-sync enforcement](2026-06-11-doc-sync-enforcement.md) already mechanized two classes of doc drift (uncompilable code blocks, a stale event-taxonomy table) and [verify-md-wrap](2026-06-11-doc-sync-enforcement.md) a third (hard-wrapped prose) — but a dead cross-link is a fourth, equally mechanical class that was still verified by eyeball. diff --git a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md index 917580ffce..61187042a3 100644 --- a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md +++ b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md @@ -1,9 +1,9 @@ -# RFC:Markdown 交叉链接有效性检查 - -[English](2026-06-18-markdown-cross-link-lint.md) | 中文 +# RFC: Markdown 交叉链接有效性检查 Status: implemented +[English](2026-06-18-markdown-cross-link-lint.md) | 中文 + ## 问题 本仓库的文档通过相对路径互相链接:`[topic](../implemented/2026-…-….md)`、`[the cookbook](adding-a-tool.md)`、`[architecture.md](../../architecture.md)`。此前没有任何机制验证这些目标是否存在。重命名或移动文件会静默破坏所有指向它的链接,且在读者点击之前不可见。[Doc-sync 强制](2026-06-11-doc-sync-enforcement.md)已经将两类文档漂移机械化(无法编译的代码块、陈旧的事件分类表),[verify-md-wrap](2026-06-11-doc-sync-enforcement.md) 覆盖了第三类(硬换行的段落),但死链是第四类同样可机械检查、却仍靠肉眼验证的问题。 @@ -20,7 +20,7 @@ Status: implemented 范围与其他门禁一致,另外加上 AGENTS.md 对和 `.agents/skills/` 下仓库自有的 agent skill Markdown(这些 skill 文件交叉链接到 docs 目录,因此本次重组也改写了其中的链接):`README.md`、`docs/**/*.md`、`packages/*/README.md`、`AGENTS.md`、`packages/AGENTS.md`、`.agents/skills/**/*.md`,按真实路径去重(`CLAUDE.md` 符号链接解析到 AGENTS.md 文件)。它接入 lefthook pre-push 钩子和 CI 都会运行的 `doc-sync` 脚本,因此死链在推送前就会在本地失败——与[机械化质量门禁](2026-06-11-quality-gates.md)一致。 -本门禁检查的是**文件存在性**,而非锚点有效性:指向一个真实文件但带有 `#wrong-heading` 片段的链接仍会通过(文件可解析;片段被剥除)。 +本门禁检查的是*文件存在性*,而非锚点有效性:指向一个真实文件但带有 `#wrong-heading` 片段的链接仍会通过(文件可解析;片段被剥除)。 ## 曾考虑的替代方案 diff --git a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml index 4345634014..7b498b0a81 100644 --- a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-core-data-structures-catalog.md: 5f1232f2f0d0644d4043af217a7177451155030b -2026-06-20-core-data-structures-catalog.zh.md: 8ad4453890d8be5dc4e743d1f6f9aa6a9330ed17 +2026-06-20-core-data-structures-catalog.md: 933844d0f442306af238bfc459372b1c97414f87 +2026-06-20-core-data-structures-catalog.zh.md: 620457b28d6b4aa36ec139da7bcd892ed78e2673 diff --git a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.md b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.md index 5f1232f2f0..933844d0f4 100644 --- a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.md +++ b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.md @@ -1,9 +1,9 @@ # RFC: Core-data-structures catalog and the `ts type-equiv` drift gate -English | [中文](2026-06-20-core-data-structures-catalog.zh.md) - Status: implemented +English | [中文](2026-06-20-core-data-structures-catalog.zh.md) + ## Problem A reader trying to understand the harness could find its *behavior* in [architecture.md](../../../architecture.md) (the service map, the session/turn/step lifecycle, the event taxonomy) but had no single place describing its *vocabulary* — the data structures that behavior moves around. The type shapes lived only in source, scattered across `packages/*/src/types.ts`, so understanding "what is a `Message`, a `SessionEvent`, a `StreamChunk`" meant reading the declarations directly. A prose catalog would help, but a catalog that paraphrases or paste-copies type definitions rots the instant a field changes — and an out-of-sync type doc is worse than none, because a reader trusts it. diff --git a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.zh.md b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.zh.md index 8ad4453890..620457b28d 100644 --- a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.zh.md +++ b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.zh.md @@ -1,4 +1,4 @@ -# RFC:核心数据结构目录与 `ts type-equiv` 漂移门禁 +# RFC: 核心数据结构目录与 `ts type-equiv` 漂移门禁 Status: implemented @@ -22,7 +22,7 @@ Status: implemented - 一个数据结构是**核心**的,如果它流经 agent loop 主干——无论加载了哪些插件,循环在每个轮次都会持有、派生、流式输出或记录它(`Message`、`StreamChunk`、`SessionEvent`、`Agent` 句柄)——**或者**它是插件作者面对某条流水线时编写的唯一标志性类型(`ToolDefinition`)。 - `ToolDefinition` 是核心(它是每个工具作者编写的东西),**即使循环从不持有它**——对于这一个标志性类型,撰写重要性压过了严格的"流经主干"规则。但它的类型推导机制——`SchemaSpec`/`InferArgs` DSL——是子页面细节(你编写的是 `ToolDefinition`;为其提供类型推导的机制你并不直接接触)。这就是主干与 seam 分界线的精确表述。 -- `ToolSchema` 是核心(它是 `GenerateOptions` 的一个字段,而 `GenerateOptions` 是流经每个步骤的模型请求),即使它在概念上属于工具流水线——当*流经主干*与*概念归属*冲突时,前者胜出。 +- `ToolSchema` 是核心(它是流经每个步骤的模型请求 `GenerateOptions` 的一个字段),即使它在概念上属于工具流水线——当*流经主干*与*概念归属*冲突时,前者胜出。 - 工具展示词汇(`ToolCallView`/`ToolResultView` 等)、`SessionPersistence` 持久性 seam 以及 bash 词汇是子页面。 `core.md` 是一份**自包含的主干文档**:它给出每个主干结构的确切类型定义,辅以最少的行文,并链接到子页面获取各 seam 的细节。子页面包括 `llm-streaming.md`、`session.md`、`persistence.md`(沿内存模型与持久性 seam 的分界线从 session 拆出)、`tools.md` 和 `bash.md`。 @@ -56,5 +56,5 @@ Status: implemented - 词汇现在有了一个**不会静默漂移**的唯一归属:源码中的字段重命名会在 pre-push 钩子和 CI 中导致 `verify-type-equiv` 失败,直到粘贴内容被刷新。 - 主干与 seam 分界线是一个可复用的范围界定工具,而非一次性的:同一条「你编写/持有/接收的东西是核心;为其提供类型推导/渲染/持久化的机制是细节」规则,后来也被用于界定事件/服务目录的 harness 层与继承层分层。 -- ` ```ts type-equiv ` 围栏是继 ` ```ts `(编译)和 ` ```ts ignore-check `(草稿)之后的第三种文档块类别。后续的姊妹门禁又增加了第四种 ` ```ts cordis-catalog `(生成签名),复用了相同的跳过并排除处理。 +- `ts type-equiv` 围栏是继 ` ```ts `(编译)和 ` ```ts ignore-check `(草稿)之后的第三种文档块类别。后续的姊妹门禁又增加了第四种 ` ```ts cordis-catalog `(生成签名),复用了相同的跳过并排除处理。 - 添加或重塑核心类型现在附带一项文档义务,作者必须履行(门禁无法检测缺失的*新*类型),由 `dsh-code-review` 检查清单兜底。 diff --git a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml index 9f7e982ff7..13f31c3ebe 100644 --- a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-generated-cordis-catalog.md: 6b451e31965f8f00210aa927ed236fed28699351 -2026-06-20-generated-cordis-catalog.zh.md: 5550d07b5f5635d1da6496e35049c5725329e114 +2026-06-20-generated-cordis-catalog.md: 8b979764c1ae6693b77817fc84381e40e56f8d36 +2026-06-20-generated-cordis-catalog.zh.md: 608ab3e0429fab43abec634ce0955f46306d8529 diff --git a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.md b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.md index 6b451e3196..8b979764c1 100644 --- a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.md +++ b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.md @@ -1,9 +1,9 @@ # RFC: Generated cordis events + services catalog -English | [中文](2026-06-20-generated-cordis-catalog.zh.md) - Status: implemented +English | [中文](2026-06-20-generated-cordis-catalog.zh.md) + ## Problem A plugin author needs two reference surfaces that no single document gave them: every cordis **event** they can listen to (with its exact signature and dispatch mode) and every `ctx.` **service** they can call (with its exact interface). The pieces existed but were scattered — a hand-maintained event-taxonomy *table* in `docs/architecture.md` (names + prose Mode/Purpose, name-set-checked by `verify-event-taxonomy`), a Service-map table (8 rows of role prose), and the `interface Events` / `interface Context` declarations themselves. The taxonomy table also could not catch a brand-new *undocumented* event: a name-set verifier only checks the names that are already in the table on both sides. diff --git a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.zh.md b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.zh.md index 5550d07b5f..608ab3e042 100644 --- a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.zh.md +++ b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.zh.md @@ -1,4 +1,4 @@ -# RFC:生成式 Cordis 事件与服务目录 +# RFC: 生成式 Cordis 事件与服务目录 Status: implemented @@ -21,8 +21,8 @@ Status: implemented 具体选择: - **`@mode` 标签,交叉校验。** 每个 harness 事件的 JSDoc 携带一个显式的 `@mode emit|waterfall|parallel|serial` 标签;缺少标签时生成器直接报错。当签名形状具有决定性时——尾部参数为 `next: () => …` 在结构上即为 waterfall(瀑布式事件)——生成器断言标签与之一致,矛盾时直接报错。emit/parallel/serial 的区别在结构上不可见(`session/flush` 返回 `Promise | void` 且无 `next`,有序的 `agent/pre-step` 检查点亦然),因此信任标签。编写规则见 [AGENTS.md](../../../../AGENTS.md)。 -- **分层范围。** harness 层(8 个 `@deepseek-ai/dsh-*` 服务及其事件)从源码完整渲染。继承层(cordis-core 的 `ctx.on/emit/effect/provide/…` + `internal/*` 事件 + loader/hmr/timer)是插件同样可见的固定 vendor 源码;它从生成器中一张人工维护的表格简洁渲染(名称 + 一行描述 + 源码指针),而**非**遍历 vendor AST。原因是 cordis-core 的 `Context` 混合了真正的 ctx 成员与非服务字段(`root`、`baseUrl`、`logger`),且 vendor 接口面仅在有意的 vendor 同步时才变化。 -- **交叉链接到数据结构目录。** 签名中的类型名(`GenerateOptions`、`StreamChunk`、`ToolDefinition` 等)链接到记录该类型的 core-data-structures 页面。映射是生成器中一个小型的人工维护常量,而**非** `type-equiv.manifest.json`——后者记录的是 `…Map` 符号,而签名引用的是派生联合类型名,且有少数符号出现在两个页面上。 +- **分层范围。** harness 层(8 个 `@deepseek-ai/dsh-*` 服务及其事件)从源码完整渲染。继承层(cordis-core 的 `ctx.on/emit/effect/provide/…` + `internal/*` 事件 + loader/hmr/timer)是插件同样可见的固定 vendor 源码;它从生成器中一张人工维护的表格简洁渲染(名称 + 一行描述 + 源码指针),而非遍历 vendor AST。原因是 cordis-core 的 `Context` 混合了真正的 ctx 成员与非服务字段(`root`、`baseUrl`、`logger`),且 vendor 接口面仅在有意的 vendor 同步时才变化。 +- **交叉链接到数据结构目录。** 签名中的类型名(`GenerateOptions`、`StreamChunk`、`ToolDefinition` 等)链接到记录该类型的 core-data-structures 页面。映射是生成器中一个小型的人工维护常量,而非 `type-equiv.manifest.json`——后者记录的是 `…Map` 符号,而签名引用的是派生联合类型名,且有少数符号出现在两个页面上。 - **专用围栏。** 签名块使用 ` ```ts cordis-catalog ` 信息字符串,`doc-typecheck` 识别后跳过(裸签名片段不能独立编译),并排除在 opt-out 比例之外——与 `type-equiv` 块获得相同待遇。 本决策**取代** [doc-sync 强制](2026-06-11-doc-sync-enforcement.md)中事件分类的那一半:`verify-event-taxonomy` 及其 `docs/architecture.md` 表格退役(architecture.md 的标题保留,正文改为指向目录;服务映射的角色表格作为人工行文保留)。doc-typecheck、verify-md-wrap、verify-md-links 和 verify-type-equiv 不受影响。 diff --git a/docs/rfc/implemented/process/2026-06-20-rfc-classification.i18n.yaml b/docs/rfc/implemented/process/2026-06-20-rfc-classification.i18n.yaml index cc4642657c..c9a4c3a6e9 100644 --- a/docs/rfc/implemented/process/2026-06-20-rfc-classification.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-20-rfc-classification.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-rfc-classification.md: 201852a209be7f40b05de45d148a36b9185767a3 -2026-06-20-rfc-classification.zh.md: 554ac8014719c99ed447a33ff843c40fde761eed +2026-06-20-rfc-classification.md: 6975b74dbaa9ca9379f23b537133323cb694958a +2026-06-20-rfc-classification.zh.md: 423d5c87eb9e2cb07ed18834f4c15ffa1ac1983e diff --git a/docs/rfc/implemented/process/2026-06-20-rfc-classification.md b/docs/rfc/implemented/process/2026-06-20-rfc-classification.md index 201852a209..6975b74dba 100644 --- a/docs/rfc/implemented/process/2026-06-20-rfc-classification.md +++ b/docs/rfc/implemented/process/2026-06-20-rfc-classification.md @@ -1,9 +1,9 @@ # RFC: Classify RFCs by kind via path-encoded subdirectories -English | [中文](2026-06-20-rfc-classification.zh.md) - Status: implemented +English | [中文](2026-06-20-rfc-classification.zh.md) + ## Problem `docs/rfc/` grouped RFCs by **lifecycle** only — `proposed/` / `implemented/` / `rejected/`. Nothing recorded what *kind* of decision each RFC was. The index was one flat list per lifecycle, with no way to scan "show me every simplification" or "every testing-strategy decision." A wave of simplification RFCs landing on the same day made the gap concrete: a reader skimming `proposed/` could not tell a new capability from a removal from a tooling-policy change without opening each file. diff --git a/docs/rfc/implemented/process/2026-06-20-rfc-classification.zh.md b/docs/rfc/implemented/process/2026-06-20-rfc-classification.zh.md index 554ac80147..423d5c87eb 100644 --- a/docs/rfc/implemented/process/2026-06-20-rfc-classification.zh.md +++ b/docs/rfc/implemented/process/2026-06-20-rfc-classification.zh.md @@ -1,9 +1,9 @@ -# RFC:通过路径编码的子目录对 RFC 进行分类 - -[English](2026-06-20-rfc-classification.md) | 中文 +# RFC: 通过路径编码的子目录对 RFC 进行分类 Status: implemented +[English](2026-06-20-rfc-classification.md) | 中文 + ## 问题 `docs/rfc/` 过去仅按**生命周期**分组 RFC:`proposed/`/`implemented/`/`rejected/`。没有任何机制记录每个 RFC 属于哪一*类*决策。索引在每个生命周期下只是一个扁平列表,无法按需筛选「所有简化类」或「所有测试策略类」决策。一批简化类 RFC 在同一天落地后,这个缺口变得具体:浏览 `proposed/` 的读者无法在不逐一打开文件的情况下区分新能力、移除和工具策略变更。 @@ -12,7 +12,7 @@ Status: implemented ## 决策 -增加第二个维度——RFC 的**类别**——并将其编码在路径中:`{lifecycle}/{class}/yyyy-mm-dd-topic.md`。文件夹本身就是标签。文件的位置声明其类别,封闭集合是「这些文件夹且仅限这些」,而既有的 [verify-md-links](2026-06-18-markdown-cross-link-lint.md) 门禁已经保护了移动文件所需的路径重写。 +增加第二个维度——RFC 的**类别**——并将其编码在路径中:`{lifecycle}/{class}/yyyy-mm-dd-topic.md`。文件夹本身*就是*标签。文件的位置声明其类别,封闭集合是「这些文件夹且仅限这些」,而既有的 [verify-md-links](2026-06-18-markdown-cross-link-lint.md) 门禁已经保护了移动文件所需的路径重写。 ### 六个类别的封闭集合 @@ -22,7 +22,7 @@ Status: implemented | `bug-fix` | 修正缺陷或填补事后复盘暴露的空白。 | | `simplification` | 移除代码、行为或对外表面积,不引入新能力。 | | `architecture` | 关于**交付源码**的结构性决策——包(package)之间的关系、运行时词汇。 | -| `process` | 围绕代码的工具、策略或工作流,而非运行时行为。 | +| `process` | **围绕**代码的工具、策略或工作流,而非运行时行为。 | | `testing` | 测试基础设施与策略。 | `architecture` 与 `process` 的分界线:**architecture** 关乎我们交付的源码;**process** 关乎围绕源码的工具与工作流。本 RFC 本身是一个 `process` 决策——它改变的是仓库的组织方式和门禁,而非 harness 的运行时行为——因此它位于 `implemented/process/` 下。 diff --git a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml index 8ecca3648d..80865d0269 100644 --- a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-02-tool-schema-catalog.md: 9a99fafd36b3546be4f51a7cd9e9a47fdaaf4c2d -2026-07-02-tool-schema-catalog.zh.md: 5860d1617ce6592c8665e4cb59304b0f6d35c99a +2026-07-02-tool-schema-catalog.md: fe7ec47ac89c157482f612a374ca8773d7d0867f +2026-07-02-tool-schema-catalog.zh.md: 1567ff5dd5c53da501a86412d0e29127d33d29f6 diff --git a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.md b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.md index 9a99fafd36..fe7ec47ac8 100644 --- a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.md +++ b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.md @@ -1,9 +1,9 @@ # RFC: Generated tool-schema catalog (boot-and-harvest) -English | [中文](2026-07-02-tool-schema-catalog.zh.md) - Status: implemented +English | [中文](2026-07-02-tool-schema-catalog.zh.md) + ## Problem The repository had no single reference for the names, descriptions, and JSON Schemas actually exposed to the model. Source declarations are scattered and runtime-composed, while the existing Cordis and data-structure catalogs cover wiring and vocabulary rather than tools. diff --git a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.zh.md b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.zh.md index 5860d1617c..1567ff5dd5 100644 --- a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.zh.md +++ b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.zh.md @@ -1,16 +1,16 @@ -# RFC:生成式工具 schema 目录(启动并采集) - -[English](2026-07-02-tool-schema-catalog.md) | 中文 +# RFC: 生成式工具 schema 目录(启动并采集) Status: implemented +[English](2026-07-02-tool-schema-catalog.md) | 中文 + ## 问题 仓库此前没有一份统一的参考文档来记录实际暴露给模型的工具名称、描述与 JSON Schema。源码声明分散各处且在运行时组合,而既有的 Cordis 目录和数据结构目录覆盖的是接线与词汇,而非工具。 ## 决策 -通过**启动每个工具插件并读取其注册的 schema** 来生成目录,而非解析源码。`scripts/gen-tool-catalog.ts` 将每个已发布的工具包(package)挂载到一个新的 Cordis `Context`(带 `SystemPrompt` + `ToolRegistry` 以及插件 `apply` 所读取的注入 seam),调用 `ctx.tools.schemas()`(即发送给模型的 `ToolSchema[]`),dispose(资源释放)该 context,然后为每个包渲染一个 `## ` 小节,每个工具一个 ` ```json ` 的 `parameters` 块。它与 `gen-cordis-catalog` / `gen-module-graph` 的 CLI(命令行界面)形态一致:默认 `--write` 重新生成,`--check` 在已提交副本陈旧时失败,输出是确定性的(按 manifest(元数据清单)排序,工具按名称排序)。`verify-tool-catalog`(即 `--check`)在 doc-sync(文档同步门禁)内运行,因此新鲜度门禁在 lefthook pre-push 和 CI 路径中与其他文档门禁一同触发。 +通过**启动每个工具插件并读取其注册的 schema** 来生成目录,而非解析源码。`scripts/gen-tool-catalog.ts` 将每个已发布的工具包(package)挂载到一个新的 Cordis `Context`(带 `SystemPrompt` + `ToolRegistry` 以及插件 `apply` 所读取的注入 seam),调用 `ctx.tools.schemas()`(即发送给模型的 `ToolSchema[]`),dispose(资源释放)该 context,然后为每个包渲染一个 `## ` 小节,每个工具一个 ` ```json ` 的 `parameters` 块。它与 `gen-cordis-catalog` / `gen-module-graph` 的 CLI(命令行界面)形态一致:默认 `--write` 重新生成,`--check` 在已提交副本陈旧时失败,输出是确定性的(按 manifest(元数据清单)排序,工具按名称排序)。`verify-tool-catalog`(即 `--check`)在 `doc-sync`(文档同步门禁)内运行,因此新鲜度门禁在 lefthook pre-push 和 CI 路径中与其他文档门禁一同触发。 ### 为何启动而非解析(核心要点) @@ -25,7 +25,7 @@ Cordis 目录是纯 TypeScript AST 遍历,因为每个事件/服务名都是 ### 恢复「不会静默遗漏」的保证 -启动有一项 AST 遍历不存在的代价:没有源码声明集合可供枚举,新工具包可能被遗忘。一个**完整性守卫**恢复了这项保证——`assertManifestComplete` 对 `packages/` 下所有 `tool-*` 包进行 glob,若有任何一个不在生成器的启动 manifest 中则直接报错。新工具包在注册之前会导致生成器失败,进而导致 doc-sync 失败。这与 Cordis 生成器通过枚举源码免费获得的结构性属性相同,只是为基于启动的生成器重新实现了一遍。 +启动有一项 AST 遍历不存在的代价:没有源码声明集合可供枚举,新工具包可能被遗忘。一个**完整性守卫**恢复了这项保证——`assertManifestComplete` 对 `packages/` 下所有 `tool-*` 包进行 glob,若有任何一个不在生成器的启动 manifest 中则直接报错。新工具包在注册之前会导致生成器失败,进而导致 `doc-sync` 失败。这与 Cordis 生成器通过枚举源码免费获得的结构性属性相同,只是为基于启动的生成器重新实现了一遍。 ### 手动维护的启动 manifest 是不可化约的策略 diff --git a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml index 6b19ed7740..d5ad8c6180 100644 --- a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-03-documentation-graph-atlas.md: d10b57e5114684ab0a2caed66fa84b84959bdf12 -2026-07-03-documentation-graph-atlas.zh.md: 6edcfbdbbc3af5808e60888acad04919ce681396 +2026-07-03-documentation-graph-atlas.md: 3cb8e685452a5b013798d0c3f661fca218b3d69d +2026-07-03-documentation-graph-atlas.zh.md: f03268c63c6d834c59af6cf831a34e5a5eaf40d7 diff --git a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.md b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.md index d10b57e511..3cb8e68545 100644 --- a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.md +++ b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.md @@ -1,9 +1,9 @@ # RFC: Documentation graph index for maintainers and SDK users -English | [中文](2026-07-03-documentation-graph-atlas.zh.md) - Status: implemented +English | [中文](2026-07-03-documentation-graph-atlas.zh.md) + ## Problem The repo already had several high-trust documentation surfaces, each on a different axis: [module-graph.md](../../../module-graph.md) is generated from package `peerDependencies`, the generated [Cordis events](../../../cordis-catalog/events.md) and [services](../../../cordis-catalog/services.md) catalogs are generated from Cordis `Events` and `Context` declarations, [tool-catalog.md](../../../tool-catalog.md) is generated by booting shipped tool plugins, and [core-data-structures/](../../../core-data-structures/core.md) uses `ts type-equiv` blocks to keep pasted type definitions synchronized with source. diff --git a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.zh.md b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.zh.md index 6edcfbdbbc..f03268c63c 100644 --- a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.zh.md +++ b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.zh.md @@ -1,9 +1,9 @@ -# RFC:面向维护者与 SDK 用户的文档关系图索引 - -[English](2026-07-03-documentation-graph-atlas.md) | 中文 +# RFC: 面向维护者与 SDK 用户的文档关系图索引 Status: implemented +[English](2026-07-03-documentation-graph-atlas.md) | 中文 + ## 问题 仓库已有若干高可信度的文档面,各自覆盖不同维度:[module-graph.md](../../../module-graph.md) 由包(package)的 `peerDependencies` 生成;生成的 [Cordis events](../../../cordis-catalog/events.md) 与 [services](../../../cordis-catalog/services.md) 目录由 Cordis 的 `Events` 和 `Context` 声明生成;[tool-catalog.md](../../../tool-catalog.md) 通过启动已发布的 tool 插件生成;[core-data-structures/](../../../core-data-structures/core.md) 使用 `ts type-equiv` 块保持粘贴的类型定义与源码同步。 diff --git a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml index 80b4958372..520426ca4b 100644 --- a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-04-cordis-jsdoc-completeness-gate.md: 44a0ddce9c929deac3e03bb421aec1d5145e65ba -2026-07-04-cordis-jsdoc-completeness-gate.zh.md: 073054072748bf6cfed09cdcc222087bcc0ed929 +2026-07-04-cordis-jsdoc-completeness-gate.md: 8eaa997eb734b32e7e4a45d96def15dc541af1d5 +2026-07-04-cordis-jsdoc-completeness-gate.zh.md: a49189b3162fbd0eba9e043c683f0fc56d0bf7d6 diff --git a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.md b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.md index 44a0ddce9c..8eaa997eb7 100644 --- a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.md +++ b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.md @@ -1,9 +1,9 @@ # RFC: JSDoc completeness gate for the cordis surface -English | [中文](2026-07-04-cordis-jsdoc-completeness-gate.zh.md) - Status: implemented +English | [中文](2026-07-04-cordis-jsdoc-completeness-gate.zh.md) + ## Problem The generated Cordis catalog enforced event dispatch modes but not complete service and event contracts. Methods could lack descriptions, and parameters or returns could be undocumented on the cross-plugin API surface where IDE guidance matters most. diff --git a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md index 0730540727..a49189b316 100644 --- a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md +++ b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md @@ -1,9 +1,9 @@ -# RFC:针对 Cordis 对外服务接口的 JSDoc 完整性门禁 - -[English](2026-07-04-cordis-jsdoc-completeness-gate.md) | 中文 +# RFC: 针对 Cordis 对外服务接口的 JSDoc 完整性门禁 Status: implemented +[English](2026-07-04-cordis-jsdoc-completeness-gate.md) | 中文 + ## 问题 生成的 Cordis 目录此前强制了事件分发模式,但未强制要求完整的服务与事件契约。方法可以缺少描述,参数或返回值可以在跨插件 API 接口上不写文档——而这恰恰是 IDE 引导最重要的地方。 @@ -12,7 +12,7 @@ AGENTS.md 中的规则(「每个导出都有解释语义的 JSDoc」)只能 ## 决策 -扩展 `scripts/gen-cordis-catalog.ts`(同一次遍历、同一个 `@mode` 先例),对其编目的所有内容强制 JSDoc 完整性。`verify-cordis-catalog` 在 `doc-sync`(文档同步门禁)内运行,CI 和 lefthook pre-push 钩子都已执行 `doc-sync`,因此门禁无需新增任何接线(质量门禁原则:单一真源)。 +扩展 `scripts/gen-cordis-catalog.ts`(同一次遍历、同一个 `@mode` 先例),对其编目的所有内容强制 JSDoc 完整性。`verify-cordis-catalog` 在 `doc-sync`(文档同步门禁)内运行,CI 和 lefthook pre-push 钩子都已执行该命令,因此门禁无需新增任何接线(质量门禁原则:单一真源)。 契约如下: diff --git a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml index d6465ad8c1..15039922c5 100644 --- a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-04-doc-tiers-and-budgets.md: ca9da847849f61f2fb244932e657cca8fec69696 -2026-07-04-doc-tiers-and-budgets.zh.md: ae34e3f04d7986f78d1b3ceeaacb3bc4c7bc64f5 +2026-07-04-doc-tiers-and-budgets.md: ddbce540c68b9b35bb7e6a48b8db8abbc3a7a398 +2026-07-04-doc-tiers-and-budgets.zh.md: d3f08d337af34b5def41792232330180123dd585 diff --git a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md index ca9da84784..ddbce540c6 100644 --- a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md +++ b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md @@ -1,9 +1,9 @@ # RFC: Documentation tiers, budgets, and the ceiling gate -English | [中文](2026-07-04-doc-tiers-and-budgets.zh.md) - Status: implemented +English | [中文](2026-07-04-doc-tiers-and-budgets.zh.md) + ## Problem Standing docs accumulated repeated rules, retold incidents, duplicated package maps, and stale RFC summaries despite existing writing guidance. Because review alone did not prevent that growth, the repository needed a mechanical budget alongside its documentation taxonomy. diff --git a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md index ae34e3f04d..d3f08d337a 100644 --- a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md +++ b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md @@ -1,9 +1,9 @@ -# RFC:文档分层、预算与上限门禁 - -[English](2026-07-04-doc-tiers-and-budgets.md) | 中文 +# RFC: 文档分层、预算与上限门禁 Status: implemented +[English](2026-07-04-doc-tiers-and-budgets.md) | 中文 + ## 问题 尽管已有写作指导,常设文档仍然积累了重复的规则、重述的事故、重复的包(package)映射和陈旧的 RFC 摘要。仅靠评审无法阻止这种膨胀,因此仓库需要在文档分类体系之外增加一道机械化的预算约束。 diff --git a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.i18n.yaml b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.i18n.yaml index 8d410ae5f8..da8988c6ea 100644 --- a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-04-generate-rfc-index-tables.md: 6a8888eda8b7cf7105a44802774bf49d6463952d -2026-07-04-generate-rfc-index-tables.zh.md: aad1652edc9de81a70a7a391700f63be9499035c +2026-07-04-generate-rfc-index-tables.md: 5d5ae258583e0fae7dcb44a23c4b41446bd233d2 +2026-07-04-generate-rfc-index-tables.zh.md: fa611e4337075501fe097fe8fc68a878a855a7c0 diff --git a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.md b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.md index 6a8888eda8..5d5ae25858 100644 --- a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.md +++ b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.md @@ -1,9 +1,9 @@ # RFC: Generate the RFC index tables -English | [中文](2026-07-04-generate-rfc-index-tables.zh.md) - Status: implemented +English | [中文](2026-07-04-generate-rfc-index-tables.zh.md) + ## Problem The RFC index's per-lifecycle/per-class tables list facts that are fully derivable: an RFC's path encodes lifecycle and class, its filename encodes the first-proposed date, and its H1 carries the title. A hand-maintained copy of those facts is also the repo's highest-contention docs hotspot: every proposal wave appends rows to the same few lines, so concurrent RFC branches conflict precisely there while agreeing everywhere else, and each conflict is resolved by hand-merging rows whose content the filesystem already knows. [The classification RFC](2026-06-20-rfc-classification.md) originally kept the index hand-written for curation's sake — but the curated part of the README is the prose, and the prose never conflicts; only the mechanical tables do. diff --git a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.zh.md b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.zh.md index aad1652edc..fa611e4337 100644 --- a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.zh.md +++ b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.zh.md @@ -1,9 +1,9 @@ -# RFC:生成 RFC 索引表 - -[English](2026-07-04-generate-rfc-index-tables.md) | 中文 +# RFC: 生成 RFC 索引表 Status: implemented +[English](2026-07-04-generate-rfc-index-tables.md) | 中文 + ## 问题 RFC 索引中按生命周期/按分类的表格所列信息完全可以推导:RFC 的路径编码了生命周期与分类,文件名编码了首次提出日期,H1 标题承载了标题文本。这些信息的手工维护副本也是仓库中冲突最频繁的文档热点:每一波提案都在同几行后追加新行,因此并发的 RFC 分支恰好在此处冲突,而其他地方完全一致;每次冲突都要手工合并那些文件系统本已知晓的行。[分类 RFC](2026-06-20-rfc-classification.md) 最初为了可策展性而保留手写索引,但 README 中真正需要策展的是行文,而行文从不冲突;冲突的只有机械表格。 @@ -13,7 +13,7 @@ RFC 索引中按生命周期/按分类的表格所列信息完全可以推导: 保留策展行文;生成列表。表格位于 [`docs/rfc/INDEX.md`](../../INDEX.md),是一个**完全生成的文件**——策展行文留在 README.md 中,README.md 不包含任何索引行。[`scripts/rfc-index.ts`](../../../../scripts/rfc-index.ts) 是共享的真源:树遍历器(拥有封闭的生命周期/分类集合与结构规则,包括对可解析 H1 的要求)和渲染器(行来自 H1 标题并去掉 `RFC: ` 前缀,加上文件名日期,按日期再按文件名排序,以 `### {Class}` 分节、按规范分类顺序分组)。两个轻量消费方共享它: - [`scripts/gen-rfc-index.ts`](../../../../scripts/gen-rfc-index.ts)(`pnpm run gen-rfc-index`)从目录树完整重写 INDEX.md。 -- [`scripts/verify-rfc-classification.ts`](../../../../scripts/verify-rfc-classification.ts)(doc-sync(文档同步门禁)的一个成员)检查结构,断言已提交的 INDEX.md 与新鲜渲染结果逐字节一致(`gen-cordis-catalog`/`verify-cordis-catalog` 模式),并拒绝在策展 README 中出现索引格式的行。新鲜度检查涵盖了索引完整性检查:从磁盘生成的表格在定义上就是完整的、标题正确的。 +- [`scripts/verify-rfc-classification.ts`](../../../../scripts/verify-rfc-classification.ts)(`doc-sync`(文档同步门禁)的一个成员)检查结构,断言已提交的 INDEX.md 与新鲜渲染结果逐字节一致(`gen-cordis-catalog`/`verify-cordis-catalog` 模式),并拒绝在策展 README 中出现索引格式的行。新鲜度检查涵盖了索引完整性检查:从磁盘生成的表格在定义上就是完整的、标题正确的。 添加、移动或删除一个 RFC 只需编辑 RFC 文件本身并运行生成器;分类 RFC 的「已否决替代方案」记录中带有替代关系的交叉链接。 diff --git a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml index 5851ab8d1c..7aba38dbc9 100644 --- a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-04-persistence-log-catalog.md: f8f831ca0470cf3b5c7634550115e67f7deac840 -2026-07-04-persistence-log-catalog.zh.md: 1daa76e2b23484ad6434f6a55482672abf456eb7 +2026-07-04-persistence-log-catalog.md: d92666fc8bafcf42542940fe399d9a3ece20c173 +2026-07-04-persistence-log-catalog.zh.md: a3524b251522050567be240f28944872e725a24e diff --git a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.md b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.md index f8f831ca04..d92666fc8b 100644 --- a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.md +++ b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.md @@ -1,9 +1,9 @@ # RFC: Generated persistence log event catalog -English | [中文](2026-07-04-persistence-log-catalog.zh.md) - Status: implemented +English | [中文](2026-07-04-persistence-log-catalog.zh.md) + ## Problem `SessionEventMap` is the on-disk vocabulary, but its declarations are split across the owning session package and declaration merges. The generated persistence catalog is the single reference for every event and payload; hand-maintained tables drift and are removed. These records are not Cordis events—observers receive them through the single `session/event` bus event—so the Cordis catalog cannot cover them. The generator discovers all declarations and the doc-sync freshness gate rejects omissions or stale output. diff --git a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.zh.md b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.zh.md index 1daa76e2b2..a3524b2515 100644 --- a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.zh.md +++ b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.zh.md @@ -1,4 +1,4 @@ -# RFC:生成式持久化日志事件目录 +# RFC: 生成式持久化日志事件目录 Status: implemented diff --git a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.i18n.yaml b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.i18n.yaml index a5e22d0911..188ebf1019 100644 --- a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-05-uniform-rfc-format.md: f67c61c0b627950cf07e7d57672324308a9462ec -2026-07-05-uniform-rfc-format.zh.md: b175c2d5b7537e793a61c95b6524d08bc4216384 +2026-07-05-uniform-rfc-format.md: 9688ad6566e88372508bbfd8d032ab6d02568716 +2026-07-05-uniform-rfc-format.zh.md: eab2505e64b813f698b4356bc52a796cbd66b948 diff --git a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.md b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.md index f67c61c0b6..9688ad6566 100644 --- a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.md +++ b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.md @@ -1,9 +1,9 @@ # RFC: One gated in-file format for RFCs -English | [中文](2026-07-05-uniform-rfc-format.zh.md) - Status: implemented +English | [中文](2026-07-05-uniform-rfc-format.zh.md) + ## Problem RFC paths encoded lifecycle and class, but file contents still mixed headings, status formats, ADR and proposal templates, and proposal-era sections in implemented records. Authors copied whichever neighbor they found, and lifecycle moves could skip the required rewrite because no gate enforced an in-file contract. diff --git a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.zh.md b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.zh.md index b175c2d5b7..eab2505e64 100644 --- a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.zh.md +++ b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.zh.md @@ -1,16 +1,16 @@ -# RFC:RFC 的统一受门禁约束的文件内格式 - -[English](2026-07-05-uniform-rfc-format.md) | 中文 +# RFC: RFC 的统一受门禁约束的文件内格式 Status: implemented +[English](2026-07-05-uniform-rfc-format.md) | 中文 + ## 问题 RFC 的路径已经编码了生命周期和分类,但文件内容仍然混杂着不同的标题风格、状态格式、ADR 与 proposal 模板,以及已实现记录中残留的 proposal 时期的章节。作者随手复制找到的任何邻近文件,生命周期迁移时可以跳过必要的改写,因为没有门禁强制执行文件内契约。 ## 决策 -[README.md § The file format](../../README.md#the-file-format) 即文件内契约:头部块(`# RFC: ` 加上无日期、与所在文件夹一致的 `Status:` 枚举,唯一的正文内容是 rejection reason);按生命周期区分的正文骨架(所有阶段都以 `Problem` 开头;`proposed/` 中为 `Proposal`/`Acceptance criteria`/`Risks`;`implemented/` 中为现在时态的 `Decision`/`Consequences` 且禁止 proposal 时期的标题;`rejected/` 中冻结 proposal 形态);必须包含 `Alternatives considered` 章节;以及规范的章节词汇表,其间的自定义技术章节保持自由形式。`pnpm run verify-rfc-format`([scripts/verify-rfc-format.ts](../../../../scripts/verify-rfc-format.ts))作为 doc-sync(文档同步门禁)的一环强制执行每条机械化条款,因此生命周期迁移时跳过改写现在会让 CI 失败,而不是依赖评审者的记忆。 +[README.md § The file format](../../README.md#the-file-format) 即文件内契约:头部块(`# RFC: <title>` 加上无日期、与所在文件夹一致的 `Status:` 枚举,唯一的正文内容是 rejection reason);按生命周期区分的正文骨架(所有阶段都以 `Problem` 开头;`proposed/` 中为 `Proposal`/`Acceptance criteria`/`Risks`;`implemented/` 中为现在时态的 `Decision`/`Consequences` 且禁止 proposal 时期的标题;`rejected/` 中冻结 proposal 形态);必须包含 `Alternatives considered` 章节;以及规范的章节词汇表,其间的自定义技术章节保持自由形式。`pnpm run verify-rfc-format`([scripts/verify-rfc-format.ts](../../../../scripts/verify-rfc-format.ts))作为 `doc-sync`(文档同步门禁)的一环强制执行每条机械化条款,因此生命周期迁移时跳过改写现在会让 CI 失败,而不是依赖评审者的记忆。 整个语料库在定义格式的同一个变更中完成了规范化,这是预发布阶段的立场:没有过渡期,不容忍双格式并存。唯一的祖父条款针对内容而非格式:替代方案是记录下来的,不是凭空编造的;因此如果一篇格式定义前的 RFC 的替代方案无法从记录中重建,它会携带 `rfc-format: alternatives-not-recorded` 这条精确注释,门禁仅对日期早于本 RFC 的文件接受该注释。 diff --git a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml index b79ff4cf97..ed24da934e 100644 --- a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-06-export-surface-jsdoc-gate.md: fd255cc6212d7f6f919ad23f999fa68b01478a73 -2026-07-06-export-surface-jsdoc-gate.zh.md: 796b5bb8f3a2a890986c73511bb63e167c831a5f +2026-07-06-export-surface-jsdoc-gate.md: c2543fe50320da70c9d75bb4a16df3b110b50c47 +2026-07-06-export-surface-jsdoc-gate.zh.md: 98cb057cc1a661d2f51b8215609fc280d549c103 diff --git a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.md b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.md index fd255cc621..c2543fe503 100644 --- a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.md +++ b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.md @@ -1,9 +1,9 @@ # RFC: Export-surface JSDoc gate -English | [中文](2026-07-06-export-surface-jsdoc-gate.zh.md) - Status: implemented +English | [中文](2026-07-06-export-surface-jsdoc-gate.zh.md) + ## Problem The [cordis JSDoc completeness gate](2026-07-04-cordis-jsdoc-completeness-gate.md) made undocumented parameters and results impossible on the cordis surface — `interface Events` members and `ctx.<key>` service classes — but that surface is a fraction of what a plugin author imports. The AGENTS.md rule "every export (and non-obvious method) has a JSDoc explaining semantics" stayed prose-checkable only by review everywhere else, and nothing at all asked for `@param`/`@returns` on ordinary exported functions. A survey at adoption found 203 under-documented module-level exports across 34 packages: seam-adjacent helpers (`runBash`, `readForEdit`, `htmlToMarkdown`), format codecs, whole undocumented interfaces and type aliases — exactly the names an IDE consumer hovers. diff --git a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md index 796b5bb8f3..98cb057cc1 100644 --- a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md +++ b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md @@ -1,9 +1,9 @@ -# RFC:导出表面 JSDoc 门禁 - -[English](2026-07-06-export-surface-jsdoc-gate.md) | 中文 +# RFC: 导出表面 JSDoc 门禁 Status: implemented +[English](2026-07-06-export-surface-jsdoc-gate.md) | 中文 + ## 问题 [Cordis JSDoc 完整性门禁](2026-07-04-cordis-jsdoc-completeness-gate.md)使得 Cordis 表面上的参数和返回值不可能缺少文档——`interface Events` 成员和 `ctx.<key>` 服务类——但这只是插件作者所导入内容的一小部分。AGENTS.md 中的规则「每个导出(以及非显而易见的方法)都必须有解释语义的 JSDoc」在其他地方只能靠评审以行文方式检查,而且没有任何机制要求普通导出函数带 `@param`/`@returns`。采纳时的一次调查发现 34 个包(package)中有 203 个文档不完整的模块级导出:seam 相关辅助函数(`runBash`、`readForEdit`、`htmlToMarkdown`)、格式编解码器、完全无文档的接口和类型别名——恰恰是 IDE 消费方悬停查看的那些名称。 @@ -19,7 +19,7 @@ Status: implemented - 导出类需要类级别的描述文字;公开方法(包括静态方法——可通过导出名称访问)遵循函数契约;公开属性和访问器需要描述文字(get/set 对由 getter 覆盖)。重载实现体免检——签名承载文档。 - 导出接口、类型别名和枚举需要声明级别的描述文字;成员级别的强制有意推迟(承载关键成员契约的 seam 服务类已在 Cordis 门禁之下)。 - 导出命名空间递归检查(在 ambient `declare` 命名空间内,每个成员隐式导出);命名空间本身仅在不与同名的已文档化声明合并时才需要描述文字(Config-namespace 惯用法只需文档化插件一次)。 -- `declare module`/`declare global` 体和 `export … from` 重导出语句被跳过:augmentation 不是包的导出,重导出的定义在其定义处检查。`export import X = N.member` 别名需要文档化**自身**——其目标可能是遍历不会访问的非导出命名空间成员——且门禁仅支持纯描述文字的目标类型:可调用、类或命名空间目标携带别名描述文字无法承载的签名/成员契约,门禁会拒绝并要求直接导出该声明。 +- `declare module`/`declare global` 体和 `export … from` 重导出语句被跳过:augmentation 不是包的导出,重导出的定义在其定义处检查。`export import X = N.member` 别名需要文档化自身——其目标可能是遍历不会访问的非导出命名空间成员——且门禁仅支持纯描述文字的目标类型:可调用、类或命名空间目标携带别名描述文字无法承载的签名/成员契约,门禁会拒绝并要求直接导出该声明。 - 其余情况按封闭原则失败:`export =` 直接拒绝;基类从未命名的参数即使作为绑定模式仍需 `@param`;dispatch 不识别的导出语句类型本身就是违规——没有任何导出形式能因遗漏而免检。 三类豁免避免门禁要求样板代码,精神与 Cordis 门禁的 `this`/`next` 豁免一致(为已豁免的名称编写文档是允许的;只有缺失才不被检查): @@ -38,7 +38,7 @@ Status: implemented ## 后果 -- 新增导出不能在无文档的情况下合入:`verify-export-jsdoc` 使 `doc-sync` 失败,而 pre-push 和 CI 已运行 `doc-sync`。采纳时发现的 203 处缺口在同一个变更中补齐,门禁以绿色状态落地。 +- 新增导出不能在无文档的情况下合入:`verify-export-jsdoc` 使 `doc-sync` 失败,而 pre-push 和 CI 已运行该门禁。采纳时发现的 203 处缺口在同一个变更中补齐,门禁以绿色状态落地。 - 导出函数必须标注返回类型(采纳时已全面满足,现在成为门禁依赖),并在 `@param` 需要命名参数时使用标识符参数。 - seam 文档是权威的:实现从其继承链继承文档,值得保留在实现上的行为说明是补充,而非必需。 - 门禁构建一个 `ts.Program`(约 6 秒)——唯一需要类型解析的文档门禁;在已编译文档片段的 `doc-sync` 内可以接受。 diff --git a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml index ccfbb1cc49..18aecd24ad 100644 --- a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-06-generated-config-catalog.md: 50ba0dc70b0d8ea54a4f93911f3a087806774626 -2026-07-06-generated-config-catalog.zh.md: 87a861bab394ec268fb3c870e848db37fa4d6fcf +2026-07-06-generated-config-catalog.md: 77c2007d4b5cd28efcfe391c2de712db3b5c107e +2026-07-06-generated-config-catalog.zh.md: 4d9b190b770432111287cedee5992d5822197feb diff --git a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.md b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.md index 50ba0dc70b..77c2007d4b 100644 --- a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.md +++ b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.md @@ -1,9 +1,9 @@ # RFC: Generated plugin config catalog -English | [中文](2026-07-06-generated-config-catalog.zh.md) - Status: implemented +English | [中文](2026-07-06-generated-config-catalog.zh.md) + ## Problem The repository had no source-backed reference for plugin configuration. Package READMEs documented fields inconsistently, did not enumerate which packages are loadable, and did not verify that runtime schemas agree with declared config types. diff --git a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.zh.md b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.zh.md index 87a861bab3..4d9b190b77 100644 --- a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.zh.md +++ b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.zh.md @@ -1,4 +1,4 @@ -# RFC:生成式插件配置目录 +# RFC: 生成式插件配置目录 Status: implemented diff --git a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.i18n.yaml index 815cf98e72..e324b52b3f 100644 --- a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-06-node-engine-floor.md: 561b6b4a124b6eaa8e2ba0756a835e35519b30b8 -2026-07-06-node-engine-floor.zh.md: 21af2da919754b1ae4667b46ef2f65c14a279b49 +2026-07-06-node-engine-floor.md: f7764c408374a329c9390635e1b92ae9a4fd9dee +2026-07-06-node-engine-floor.zh.md: c46bf5168007b97878319e5f333b5bb1ab1d8f2a diff --git a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.md b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.md index 561b6b4a12..f7764c4083 100644 --- a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.md +++ b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.md @@ -1,9 +1,9 @@ # RFC: Raise the Node LTS engine floor to 22.19 -English | [中文](2026-07-06-node-engine-floor.zh.md) - Status: implemented +English | [中文](2026-07-06-node-engine-floor.zh.md) + ## Problem The Node 22 branch of the root `engines.node` range is a contract for the installed workspace, not only for the runtime APIs the harness source calls directly. It must be no lower than package `engines.node` declarations for dependencies the workspace installs on that branch; otherwise `pnpm install --engine-strict` fails at an advertised LTS version, and non-strict installs run outside a dependency's supported runtime. diff --git a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.zh.md b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.zh.md index 21af2da919..c46bf51680 100644 --- a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.zh.md +++ b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.zh.md @@ -1,9 +1,9 @@ -# RFC:将 Node LTS 引擎下限提升至 22.19 - -[English](2026-07-06-node-engine-floor.md) | 中文 +# RFC: 将 Node LTS 引擎下限提升至 22.19 Status: implemented +[English](2026-07-06-node-engine-floor.md) | 中文 + ## 问题 根 `engines.node` 范围中的 Node 22 分支是对已安装工作区的契约,而不仅仅是 harness 源码直接调用的运行时 API 的契约。它不得低于工作区在该分支上安装的依赖所声明的 package `engines.node`;否则 `pnpm install --engine-strict` 会在一个已宣传的 LTS 版本上失败,而非严格模式的安装则会在依赖所支持的运行时范围之外运行。 diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml index 7abfb8a8ed..40132b2b97 100644 --- a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-06-parallel-github-ci-gates.md: 890adf58ac8a20a39806aa028d035cb253d5a4f1 -2026-07-06-parallel-github-ci-gates.zh.md: 47562ed6a83b650a3275b4045c39c4de6d2ecac6 +2026-07-06-parallel-github-ci-gates.md: 6a9bd339304c8efac7a29bdbe745270ab9661396 +2026-07-06-parallel-github-ci-gates.zh.md: 24fdf27822aac7640fbeaf602fa8dd84277083fa diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.md b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.md index 890adf58ac..6a9bd33930 100644 --- a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.md +++ b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.md @@ -1,9 +1,9 @@ # RFC: Parallel GitHub CI gates -English | [中文](2026-07-06-parallel-github-ci-gates.zh.md) - Status: implemented +English | [中文](2026-07-06-parallel-github-ci-gates.zh.md) + ## Problem The keyless GitHub CI gates are mostly orthogonal: typecheck, lint, documentation freshness, coverage, snapshot replay, build, package-publication hygiene, demo smoke, and built-bin smoke fail for different reasons and do not need each other's runtime state. Running them as one ordered command chain makes the workflow wall clock equal the sum of those gates, while splitting every leaf gate into its own GitHub job repeats checkout, Node setup, pnpm restore, and install work until orchestration overhead becomes the bottleneck. diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md index 47562ed6a8..24fdf27822 100644 --- a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md +++ b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md @@ -1,9 +1,9 @@ -# RFC:并行 GitHub CI 门禁 - -[English](2026-07-06-parallel-github-ci-gates.md) | 中文 +# RFC: 并行 GitHub CI 门禁 Status: implemented +[English](2026-07-06-parallel-github-ci-gates.md) | 中文 + ## 问题 keyless GitHub CI 门禁大多相互正交:类型检查、lint、文档新鲜度、覆盖率、快照回放、构建、包发布卫生检查、demo 冒烟测试与 built-bin 冒烟测试各自因不同原因失败,彼此不需要对方的运行时状态。将它们串成一条有序命令链,工作流的挂钟时间等于所有门禁之和;而把每个叶子门禁拆成独立的 GitHub job,则会重复 checkout、Node 设置、pnpm restore 和 install 工作,直到编排开销本身成为瓶颈。 diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml index 6475a65971..e3e1c0d234 100644 --- a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-06-parallel-pre-push-gates.md: 8a8813f2f3f6726ab2ab028757406d366ceb8b6d -2026-07-06-parallel-pre-push-gates.zh.md: 6ee3a8003853092d75cda9908bfae13ee0d4c7a2 +2026-07-06-parallel-pre-push-gates.md: cf032f8dfedd88a7d6be87999fd9786a9efbb2e8 +2026-07-06-parallel-pre-push-gates.zh.md: 776faf1f46c6490f1935727612225414dd258aa3 diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.md b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.md index 8a8813f2f3..cf032f8dfe 100644 --- a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.md +++ b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.md @@ -1,9 +1,9 @@ # RFC: Parallel pre-push gates -English | [中文](2026-07-06-parallel-pre-push-gates.zh.md) - Status: implemented +English | [中文](2026-07-06-parallel-pre-push-gates.zh.md) + ## Problem The pre-push hook is the last local checkpoint before a branch leaves the machine, so its wall clock directly shapes whether contributors keep it enabled and trust its signal. Lefthook already runs top-level jobs in parallel, but aggregate jobs such as `pnpm run hygiene` and `pnpm run doc-sync` hide long sequential chains inside one job. The hook can therefore be configured as parallel while still waiting on serial subcommands whose members are independent. diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md index 6ee3a80038..776faf1f46 100644 --- a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md +++ b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md @@ -1,9 +1,9 @@ -# RFC:并行 pre-push 门禁 - -[English](2026-07-06-parallel-pre-push-gates.md) | 中文 +# RFC: 并行 pre-push 门禁 Status: implemented +[English](2026-07-06-parallel-pre-push-gates.md) | 中文 + ## 问题 pre-push 钩子是分支离开本地机器前的最后一道检查点,因此它的挂钟时间直接影响贡献者是否愿意保持启用并信任其信号。Lefthook 已经能并行运行顶层 job,但 `pnpm run hygiene` 和 `pnpm run doc-sync` 等聚合 job 在单个 job 内部隐藏了长串的顺序执行链。钩子因此可能在配置上看似并行,实际仍在等待那些成员彼此独立却串行执行的子命令。 diff --git a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml index 81355776bb..69cfd7e0db 100644 --- a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-10-readme-known-limitations-gate.md: b7f45421bf0d4d50ec1a19941934e782f52e7926 -2026-07-10-readme-known-limitations-gate.zh.md: dc023ac43890d8aaaefaece2e592001629e2a74e +2026-07-10-readme-known-limitations-gate.md: 1aad1d40285f295833c2b1bd7d5c2e71bb780f34 +2026-07-10-readme-known-limitations-gate.zh.md: 4b3904fac3f980f9d005907775618cd28778a6fe diff --git a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.md b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.md index b7f45421bf..1aad1d4028 100644 --- a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.md +++ b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.md @@ -1,9 +1,9 @@ # RFC: A gated Known-Limitations section in every package README -English | [中文](2026-07-10-readme-known-limitations-gate.zh.md) - Status: implemented +English | [中文](2026-07-10-readme-known-limitations-gate.zh.md) + ## Problem The [documentation standard](../../../AGENTS.md) assigns limitations to package READMEs. Without a shared shape, an omitted section cannot distinguish an audited absence from forgotten documentation, and variant headings prevent a repository-wide search. diff --git a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md index dc023ac438..4b3904fac3 100644 --- a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md +++ b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md @@ -1,9 +1,9 @@ -# RFC:在每个 package README 中设置受门禁保护的 Known Limitations 章节 - -[English](2026-07-10-readme-known-limitations-gate.md) | 中文 +# RFC: 在每个 package README 中设置受门禁保护的 Known Limitations 章节 Status: implemented +[English](2026-07-10-readme-known-limitations-gate.md) | 中文 + ## 问题 [文档标准](../../../AGENTS.md)将限制事项指定在 package README 中记录。如果没有统一的格式,缺失的章节无法区分「经审计确认无此内容」与「忘了写文档」,而标题写法不一致也会妨碍全仓库搜索。 diff --git a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml index 9e9b379eb9..4a0af0834e 100644 --- a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-12-package-model-experience-contract.md: 036efbc9510d6d0ae9e3c52a5ba8f39647adc4c9 -2026-07-12-package-model-experience-contract.zh.md: b1efa712bc4f6fa7b23c0afe965e56eabf068d97 +2026-07-12-package-model-experience-contract.md: 28a1c75ca6f451b4ca2f6da6abf36f72c5d43b31 +2026-07-12-package-model-experience-contract.zh.md: 77fa7a67847ed186b65db57b6dda378a93b94d92 diff --git a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.md b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.md index 036efbc951..28a1c75ca6 100644 --- a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.md +++ b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.md @@ -1,9 +1,9 @@ # RFC: Package Model Experience contract -English | [中文](2026-07-12-package-model-experience-contract.zh.md) - Status: implemented +English | [中文](2026-07-12-package-model-experience-contract.zh.md) + ## Problem A package README can explain APIs and runtime mechanics without answering the question that dominates an agent harness's behavior and cost: what from this package reaches a model request, under which conditions, and how long those tokens remain. The omission is especially hard to audit in a plugin architecture. A consumer may turn a backend result into a tool message, a policy plugin may replace success with an error, compaction may remove old history, and an agent-scoped registration may change one agent's prompt or schemas while leaving every other agent unchanged. Reading only the nominally model-facing packages therefore misses real context effects, while reading source across every dependency is too expensive for routine review. diff --git a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.zh.md b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.zh.md index b1efa712bc..77fa7a6784 100644 --- a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.zh.md +++ b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.zh.md @@ -1,9 +1,9 @@ -# RFC:Package Model Experience 契约 - -[English](2026-07-12-package-model-experience-contract.md) | 中文 +# RFC: Package Model Experience 契约 Status: implemented +[English](2026-07-12-package-model-experience-contract.md) | 中文 + ## 问题 一个 package(包)的 README 可以解释 API 和运行时机制,却不回答那个主导 agent harness(智能体框架)行为与成本的问题:本 package 中有什么内容会进入模型请求、在什么条件下进入、以及这些 token 会保留多久。在插件架构中,这一缺失尤其难以审计。消费方可能把后端结果转为工具消息,策略插件可能把成功替换为错误,上下文压缩(context compaction)可能移除旧历史,agent 作用域的注册可能改变某个 agent 的提示词或 schema 而其他 agent 不受影响。因此,只阅读名义上面向模型的 package 会遗漏真实的上下文影响,而跨所有依赖阅读源码对日常评审来说又太昂贵。 @@ -16,7 +16,7 @@ Status: implemented 没有模型上下文效应的 package,或其路径完全由另一个 package 渲染的 package,使用验证器审计过的单句形式:`None, as ` 或 `Indirectly, through `。纯传输和无密钥的测试支持 package 在不创建模型绑定内容时使用 none 形式。提供方后端即使对数据进行上限或过滤,也使用 indirect 形式;组装 bundle 在命名子 package 拥有全部效应时同样使用 indirect 形式。这些句子定位贡献所在,而不重述消费方的内容。结构化章节同样只记录 package 自身拥有的输入、变换和差异。 -`verify-package-readme-model-experience` 发现 package manifest(元数据清单)并验证三种分类、规范的末尾章节顺序、必填字段、具体字面量证据、嵌套逐字块和锚定的工具目录链接。它在 doc-sync(文档同步门禁)和并行门禁运行器中执行。覆盖面、链接相关性和事实准确性仍由评审把关。 +`verify-package-readme-model-experience` 发现 package manifest(元数据清单)并验证三种分类、规范的末尾章节顺序、必填字段、具体字面量证据、嵌套逐字块和锚定的工具目录链接。它在 `doc-sync`(文档同步门禁)和并行门禁运行器中执行。覆盖面、链接相关性和事实准确性仍由评审把关。 ## 曾考虑的替代方案 diff --git a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml index 7d48003ed6..d94f825076 100644 --- a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-19-drop-mutable-session-summary.md: 0d790191906a9128ad12d40526fde3b9f8fa939f -2026-06-19-drop-mutable-session-summary.zh.md: 6b234eb0dbdf764223e078519c810216c28603be +2026-06-19-drop-mutable-session-summary.md: 0f005a78045869d62eb141c9bce8af037671b687 +2026-06-19-drop-mutable-session-summary.zh.md: a33b057c2177258e0e3e2c0c3f78176835acb070 diff --git a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.md b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.md index 0d79019190..0f005a7804 100644 --- a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.md +++ b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.md @@ -1,9 +1,9 @@ # RFC: Drop the mutable session summary -English | [中文](2026-06-19-drop-mutable-session-summary.zh.md) - Status: implemented +English | [中文](2026-06-19-drop-mutable-session-summary.zh.md) + ## Problem The [session-persistence seam](../architecture/2026-06-14-session-persistence.md) split a session's out-of-log metadata into two types owned by `dsh-session`: an immutable `SessionHeader` (`version`, `id`, `createdAt`, `cwd?`, `parentSession?`) written once at creation, and a mutable `SessionSummary` (`updatedAt`, `title?`, `firstPrompt?`) "updateable without touching the append-only log". Their union was `SessionMeta = SessionHeader & SessionSummary`, and the abstract `SessionPersistence` service carried a seventh method — `update(id, summary)` — for rewriting the summary. Each backend implemented the mutable store its own way: JSONL wrote a separate atomic `.summary.json` **sidecar** beside the log (temp-write + rename, best-effort), SQLite kept `updated_at`/`title`/`first_prompt` **columns** bumped inside the append transaction. diff --git a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md index 6b234eb0db..a33b057c21 100644 --- a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md @@ -1,4 +1,4 @@ -# RFC:移除可变的会话摘要 +# RFC: 移除可变的会话摘要 Status: implemented @@ -12,7 +12,7 @@ Status: implemented - `SessionPersistence.update()` **零个生产调用方**(所有 `.update(` 匹配都是 `createHash().update()` 或测试代码)。 - `firstPrompt` 在生产代码中**从未被读取**。 -- `title` 确实在 ACP 桥接层被读取过,但读的是工具调用的 **presenter**(`present.title`),从未读取存储的会话元数据。 +- `title` *确实*在 ACP 桥接层被读取过,但读的是工具调用的 **presenter**(`present.title`),从未读取存储的会话元数据。 - `updatedAt` **没有消费方**:`list()` 唯一的生产调用方读取的是 `meta.cwd`(`SessionHeader` 字段),用于在 `session/load` 时校验工作区;恢复会话读取的是 `createdAt`/`cwd`/`parentSession`——全是 header 字段。 - 决定性的一点:活跃的 `Session.header` 类型本来就是 `SessionHeader` 而非 `SessionMeta`——摘要从未存在于活跃会话对象上;它只存在于持久化层,除了自身的契约测试外无人写入、无人读取。 @@ -20,13 +20,13 @@ Status: implemented 彻底删除可变的会话摘要。`SessionSummary` 与 `SessionMeta` 这个名称一并移除;后端存储和返回的元数据仅为 `SessionHeader`。`SessionPersistence.update()` 从抽象服务和所有后端中移除。JSONL 去掉整套伴随文件机制(`writeSidecar`/`readSidecar`/`touchSummary`/`removeSidecars`/`sidecarPath` 以及 load/list 的覆盖逻辑);SQLite 去掉 `updated_at`/`title`/`first_prompt` 列以及每次追加时的 `updated_at` 更新,其 `SCHEMA_VERSION` 从 `1 → 2`。 -摘要原本要提供的一切,在消费方真正需要时都**可从仅追加日志中派生**(`firstPrompt` = 第一条 `user/message`;近期度 = 最后一个事件的 `time` 或文件 mtime),或者已经存在于不可变 header 中(`createdAt`、`cwd`)。唯一不可派生的是用户*手动编辑*的标题,但它从未实现,纯属 YAGNI;如果未来真有功能需要,它可以作为独立的日志事件或 header 字段回归。 +摘要原本要提供的一切,在消费方真正需要时都**可从仅追加日志中派生**(`firstPrompt` = 第一条 `user/message`;近期度 = 最后一个事件的 `time` 或文件 mtime),或者已经存在于不可变 header 中(`createdAt`、`cwd`)。唯一*不可*派生的是用户*手动编辑*的标题,但它从未实现,纯属 YAGNI;如果未来真有功能需要,它可以作为独立的日志事件或 header 字段回归。 将此记录为决策,原因有三:**持久性**(它收窄了一个公开服务契约和跨两个后端的磁盘格式)、**争议性**(摘要是有意的前瞻性设计,而非意外产物)、**意外性**(未来读者看到 `SessionHeader` 而原始 RFC 描述的是 `SessionMeta`,否则会疑惑摘要为何消失)。它还为 [shared persistence write coordinator](../architecture/2026-06-18-shared-persistence-write-coordinator.md) 扫清了障碍:没有可变摘要后,协调器的钩子接口无需 `updateSummary` 钩子,JSONL 伴随文件与 SQLite 列之间的持久性分歧也随之消失,两个后端的写入路径得以统一。 ## 无需迁移 -这是未发布的软件(见[根 AGENTS.md](../../../../AGENTS.md)「Pre-release stance: foundation over blast radius」一节),因此没有需要保留的磁盘数据库或日志。SQLite 不迁移 v1 数据库:`openDatabase` 守卫现在拒绝任何非当前版本的磁盘 `user_version`(`onDisk !== 0 && onDisk !== SCHEMA_VERSION`),无论更旧还是更新,因此陈旧的 v1 数据库会被干净地拒绝,而非在新列集下被半读取。新建数据库写入当前版本号;这是唯一需要正常工作的路径。 +这是未发布的软件(见[根 AGENTS.md](../../../../AGENTS.md)「Pre-release stance: foundation over blast radius」一节),因此没有需要保留的磁盘数据库或日志。SQLite 不迁移 v1 数据库:`openDatabase` 守卫现在拒绝任何非当前版本的磁盘 `user_version`(`onDisk !== 0 && onDisk !== SCHEMA_VERSION`),无论更旧*还是*更新,因此陈旧的 v1 数据库会被干净地拒绝,而非在新列集下被半读取。新建数据库写入当前版本号;这是唯一需要正常工作的路径。 ## 后果 diff --git a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml index 807d67d2fc..784b07f47b 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-collapse-trace-only-session-events.md: 9156c2ab356b1c46758d9d2047d491cd1952cbc4 -2026-06-20-collapse-trace-only-session-events.zh.md: c4555f3a772096fc36de968d5d3085f5a2e879f3 +2026-06-20-collapse-trace-only-session-events.md: c446f43d887088fcf562305fcc2dad37465fb124 +2026-06-20-collapse-trace-only-session-events.zh.md: eda7f738abbaced393f2588867f9dcd8e86e2386 diff --git a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.md b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.md index 9156c2ab35..c446f43d88 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.md +++ b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.md @@ -1,9 +1,9 @@ # RFC: Fold trace-only session facts into load-bearing events -English | [中文](2026-06-20-collapse-trace-only-session-events.zh.md) - Status: implemented +English | [中文](2026-06-20-collapse-trace-only-session-events.zh.md) + ## Problem The session event vocabulary includes first-class events that are not part of replayable conversation history and have little or no production consumption. `usage` is already present as a model stream chunk before the loop also appends a separate `usage` event. `error` duplicates the `turn/end { kind: 'error', message, code }` reason for loop failures; ACP settlement reads the turn-end reason, ACP rendering ignores the `error` event, and `deriveMessages()` skips it. diff --git a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md index c4555f3a77..eda7f738ab 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md @@ -1,4 +1,4 @@ -# RFC:将仅用于追踪的会话事实折叠进承载性事件 +# RFC: 将仅用于追踪的会话事实折叠进承载性事件 Status: implemented diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml index dbb62e578d..7534bcc2da 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-drop-unconsumed-llm-adapter-change-event.md: efe90c0197671ef4385ce517540b4b238962c3b5 -2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md: b26610cfe273820112113c73b9313557cd78262c +2026-06-20-drop-unconsumed-llm-adapter-change-event.md: 657e5f08c02e1e03eedeccf8a30b8bc851201615 +2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md: fbc2248c8357dbff3f5f5008647c14c23a66d5b0 diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md index efe90c0197..657e5f08c0 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md @@ -1,9 +1,9 @@ # RFC: Drop the unconsumed `llm/adapter-change` event -English | [中文](2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md) - Status: implemented +English | [中文](2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md) + ## Problem `LlmService.registerAdapter()` emits `llm/adapter-change` on registration and disposal ([packages/llm/llm/src/index.ts](../../../../packages/llm/llm/src/index.ts)). Grepping `llm/adapter-change` across `packages/*/src` and `examples/*/src` finds only the declaration, emit sites, docs, and tests; no production listener subscribes to it. diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md index b26610cfe2..fbc2248c83 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md @@ -1,4 +1,4 @@ -# RFC:移除未被消费的 `llm/adapter-change` 事件 +# RFC: 移除未被消费的 `llm/adapter-change` 事件 Status: implemented diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml index 0d895a2b35..f9986e5608 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-drop-unconsumed-llm-assembled-surfaces.md: c8999dd0e19b2c8eaff854c8ff544bae2fc068b6 -2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md: de297a8cb64d9002fce2c857fd3caa5f2b25f43a +2026-06-20-drop-unconsumed-llm-assembled-surfaces.md: ead3a8c094b0fc0b4bd01671bd4a1165dd555ea2 +2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md: 16704b511151c329622e58c3b5f6b2cff330f366 diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.md b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.md index c8999dd0e1..ead3a8c094 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.md +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.md @@ -1,9 +1,9 @@ # RFC: Drop unconsumed assembled LLM convenience surfaces -English | [中文](2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md) - Status: implemented +English | [中文](2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md) + ## Problem `LlmService` ([packages/llm/llm/src/index.ts](../../../../packages/llm/llm/src/index.ts)) exposes three call surfaces over a model: diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md index de297a8cb6..16704b5111 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md @@ -1,4 +1,4 @@ -# RFC:移除未被消费的 LLM 组装便捷接口 +# RFC: 移除未被消费的 LLM 组装便捷接口 Status: implemented diff --git a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml index e995e57540..b777318d66 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-prune-dead-seam-methods.md: cb3eb576dbae209ddccbea7f42a80ef09f842887 -2026-06-20-prune-dead-seam-methods.zh.md: 988da3c44d8860d89f090f0ea9e2af49ae9007dd +2026-06-20-prune-dead-seam-methods.md: fc656f4fc46837a75fa6c34c2de18cffde954ef3 +2026-06-20-prune-dead-seam-methods.zh.md: 2b8b2afea97aa28d32d55a9def217a593e9dbc7d diff --git a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.md b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.md index cb3eb576db..fc656f4fc4 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.md +++ b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.md @@ -1,9 +1,9 @@ # RFC: Prune dead methods from the persistence seam -English | [中文](2026-06-20-prune-dead-seam-methods.zh.md) - Status: implemented +English | [中文](2026-06-20-prune-dead-seam-methods.zh.md) + > **Implementation note:** Only `SessionPersistence.has()` and `.delete()` were removed. `BashExecutor.get()` and `.list()` remain because removing their one-line lookup surface required substantially more completion-tracking machinery in consumers. Their id branding is covered by the [branded-ids RFC](../architecture/2026-06-20-branded-ids.md). ## Problem diff --git a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md index 988da3c44d..2b8b2afea9 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md @@ -1,9 +1,9 @@ -# RFC:从 persistence seam 中移除无用方法 - -[English](2026-06-20-prune-dead-seam-methods.md) | 中文 +# RFC: 从 persistence seam 中移除无用方法 Status: implemented +[English](2026-06-20-prune-dead-seam-methods.md) | 中文 + > **实现说明:** 最终只移除了 `SessionPersistence.has()` 和 `.delete()`。`BashExecutor.get()` 和 `.list()` 保留,因为移除它们的单行查询接口需要在消费方引入大量额外的完成状态追踪机制。它们的 id 品牌化由 [branded-ids RFC](../architecture/2026-06-20-branded-ids.md) 覆盖。 ## 问题 diff --git a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml index 68ba79e73a..eec7c0f05d 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-public-agent-stop-surface.md: 8c371911616b0a156156355b2ca15d795cfd21e5 -2026-06-20-public-agent-stop-surface.zh.md: bbd61fa1738fda64ec5e068dae84062163937c1a +2026-06-20-public-agent-stop-surface.md: d34f21be66892e261f1435070aaf9b478c8dc7cd +2026-06-20-public-agent-stop-surface.zh.md: a510d39044048637c2462fd1d97eb3474931761a diff --git a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.md b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.md index 8c37191161..d34f21be66 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.md +++ b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.md @@ -1,9 +1,9 @@ # RFC: Keep one public stop primitive -English | [中文](2026-06-20-public-agent-stop-surface.zh.md) - Status: implemented +English | [中文](2026-06-20-public-agent-stop-surface.zh.md) + > **Implementation note:** Only `abort()` was removed. `whenIdle()` remains because it is the public quiescence signal and safely handles waiter settlement and replacement-turn races; consumers should not reconstruct that behavior from status transitions. ## Problem diff --git a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md index bbd61fa173..a510d39044 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md @@ -1,4 +1,4 @@ -# RFC:保留单一公开停止原语 +# RFC: 保留单一公开停止原语 Status: implemented diff --git a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml index ec11d8ea9a..16911f7c70 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-remove-agent-boundary-mirror-events.md: 46b5e43951885915d4c3dd3f867ced6c31d32035 -2026-06-20-remove-agent-boundary-mirror-events.zh.md: 15be07f43997b1d899f0297d311c3ad83f088ee0 +2026-06-20-remove-agent-boundary-mirror-events.md: 0ea8512ca6b66b2e8ab8cf2746bdc65d79caa9d4 +2026-06-20-remove-agent-boundary-mirror-events.zh.md: 30632bf223cb41c18f62c18a544ff42f70af1136 diff --git a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md index 46b5e43951..0ea8512ca6 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md +++ b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md @@ -1,9 +1,9 @@ # RFC: Stop mirroring durable boundaries as agent events -English | [中文](2026-06-20-remove-agent-boundary-mirror-events.zh.md) - Status: implemented +English | [中文](2026-06-20-remove-agent-boundary-mirror-events.zh.md) + ## Problem The loop exposed durable turn and step boundaries through both the replayable `SessionEvent` log and live `agent/*` mirrors. Consumers had to choose between two sources for the same fact and reconcile their timing. ACP and persistence already used the log; the stdio UI was the only remaining mirror consumer and already rendered tool calls and results from `session/event`. diff --git a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md index 15be07f439..30632bf223 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md @@ -1,9 +1,9 @@ -# RFC:停止将持久化边界镜像为 agent 事件 - -[English](2026-06-20-remove-agent-boundary-mirror-events.md) | 中文 +# RFC: 停止将持久化边界镜像为 agent 事件 Status: implemented +[English](2026-06-20-remove-agent-boundary-mirror-events.md) | 中文 + ## 问题 agent loop(智能体循环)通过可回放的 `SessionEvent` 日志和实时 `agent/*` 镜像两条路径暴露持久化的轮次与步骤边界。消费方不得不在同一事实的两个来源之间做选择,并协调二者的时序。ACP(Agent Client Protocol)和持久化层已经使用日志;stdio UI 是唯一仍在消费镜像的组件,而它已经从 `session/event` 渲染工具调用和工具结果。 diff --git a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml index aecab4f6b5..f1fa61c3c2 100644 --- a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-26-fsspec-style-fs-seam.md: 493af9341177aaaed4cdca03a3c20f326c5c4dac -2026-06-26-fsspec-style-fs-seam.zh.md: 4aa9b260396c22433ea9a4c9af0b4101fa6895e7 +2026-06-26-fsspec-style-fs-seam.md: 7b5e61481eeca9556de58cf3d6f8fe935b2eefb5 +2026-06-26-fsspec-style-fs-seam.zh.md: 72d37c196df99d110ea59c5108dc9de084669c8b diff --git a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.md b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.md index 493af93411..7b5e61481e 100644 --- a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.md +++ b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.md @@ -1,9 +1,9 @@ # RFC: Split the filesystem seam — provider text mutations plus the `dsh-fs-policy` plugin -English | [中文](2026-06-26-fsspec-style-fs-seam.zh.md) - Status: implemented +English | [中文](2026-06-26-fsspec-style-fs-seam.zh.md) + ## Problem The filesystem capability from [filesystem-capability-seam](../../implemented/architecture/2026-06-17-filesystem-capability-seam.md) currently makes one abstract `FileSystem` service own two different jobs: diff --git a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md index 4aa9b26039..72d37c196d 100644 --- a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md @@ -1,9 +1,9 @@ -# RFC:拆分文件系统 seam——提供方文本变更操作与 `dsh-fs-policy` 插件 - -[English](2026-06-26-fsspec-style-fs-seam.md) | 中文 +# RFC: 拆分文件系统 seam——提供方文本变更操作与 `dsh-fs-policy` 插件 Status: implemented +[English](2026-06-26-fsspec-style-fs-seam.md) | 中文 + ## 问题 [filesystem-capability-seam](../../implemented/architecture/2026-06-17-filesystem-capability-seam.md) 中引入的文件系统能力目前让一个抽象的 `FileSystem` 服务承担两类不同的职责: @@ -30,7 +30,7 @@ provider dsh-fs-local local implementation of ctx.fs `dsh-tool-fs` 保持相同的面向模型的 `read`/`write`/`edit` schema。它是执行器:注入 `fs`(不是策略服务)并直接访问 `ctx.fs`,拥有读取窗口化逻辑,并分发 `fs/*` 事件以便 `dsh-fs-policy` 进行门控和记录。 -本 RFC 决定了四层拆分、提供方契约和新鲜度策略。工具↔策略的**耦合方式**随后由[事件门控 RFC](../architecture/2026-06-26-file-context-as-event-gate.md) 细化:`dsh-fs-policy` 是一个门控**插件**,通过 `fs/*` 事件参与而非提供 `ctx.fileContext` 方法服务,因此工具不与它产生方法耦合,读取窗口化与 fs I/O 留在 `dsh-tool-fs` 中。本文描述的是最终落地的事件门控形态;提供方的版本守卫是可选的(省略 = 无条件裸提供方)。 +本 RFC 决定了四层拆分、提供方契约和新鲜度策略。工具↔策略的耦合方式随后由[事件门控 RFC](../architecture/2026-06-26-file-context-as-event-gate.md) 细化:`dsh-fs-policy` 是一个门控插件,通过 `fs/*` 事件参与而非提供 `ctx.fileContext` 方法服务,因此工具不与它产生方法耦合,读取窗口化与 fs I/O 留在 `dsh-tool-fs` 中。本文描述的是最终落地的事件门控形态;提供方的版本守卫是可选的(省略 = 无条件裸提供方)。 ## 提供方契约 @@ -61,9 +61,9 @@ type FsWriteIntent = `writeText` 是原子的临时文件 + rename,带有显式的写入期望。`createIfAbsent` 创建不存在的目标,对已存在的目标以 `FS_NOT_OBSERVED` 拒绝;这是 owner 没有先前读取时使用的路径。`replaceIfVersion` 仅在目标以观测到的版本存在时替换;目标不存在或版本不匹配时抛出 `FS_STALE_VERSION`。 -`editText` 是提供方级别的受保护文本变更。启用守卫时,它首先验证目标仍以 `expected.version` 存在,然后读取当前文本、应用字面替换并原子写入。过期检查必须在字面匹配之前发生,这样基于旧读取的编辑会报告 `FS_STALE_VERSION`,而不是对更新内容进行匹配后报告 `FS_EDIT_NOT_FOUND` 或 `FS_AMBIGUOUS_EDIT`。将此原语保留在提供方 seam 上,保持了后端本地锁定的能力,也让未来的远程后端能够实现原生的 compare-and-edit,而无需策略层拉取整个文件。 +`editText` 是提供方级别的受保护文本变更。启用守卫时,它首先验证目标仍以 `expected.version` 存在,然后读取当前文本、应用字面替换并原子写入。陈旧检查必须在字面匹配之前发生,这样基于旧读取的编辑会报告 `FS_STALE_VERSION`,而不是对更新内容进行匹配后报告 `FS_EDIT_NOT_FOUND` 或 `FS_AMBIGUOUS_EDIT`。将此原语保留在提供方 seam 上,保持了后端本地锁定的能力,也让未来的远程后端能够实现原生的 compare-and-edit,而无需策略层拉取整个文件。 -这是一个*文本存储* seam,刻意比字节级 fsspec(`cat`/`open` 返回原始字节)高半个层次。UTF-8 解码、二进制/NUL 拒绝、受保护的全文件写入和受保护的字面文本编辑都在提供方内完成,因此策略层从不接触原始字节、不重新实现跨分片解码、也不将过期检查与变更临界区分离。面向模型的概念仍然不下沉到提供方:行窗口、带行号的行、渲染的页脚、观测状态存储都不会泄漏下去。 +这是一个*文本存储* seam,刻意比字节级 fsspec(`cat`/`open` 返回原始字节)高半个层次。UTF-8 解码、二进制/NUL 拒绝、受保护的全文件写入和受保护的字面文本编辑都在提供方内完成,因此策略层从不接触原始字节、不重新实现跨分片解码、也不将陈旧检查与变更临界区分离。面向模型的概念仍然不下沉到提供方:行窗口、带行号的行、渲染的页脚、观测状态存储都不会泄漏下去。 从 `dsh-fs` 中删除的内容:`readPage`、`FsExpectation`、`FsView`、`FsStateSource`、`FsReadRequest`、`FsTextLine`、行/窗口常量、`formatReadBody`,以及观测状态 `WeakMap`。`applyEdit` 被更窄的提供方原语 `editText` 取代,后者的契约是版本守卫的字面文本变更,而非策略层的读取授权。`FS_PARTIAL_OBSERVATION` 错误码也从 `FsErrorCode` 分类体系中移除:新鲜度授权没有 partial/full 之分,因此没有什么能触发它。`FsTargetKey` 和 `FsVersion` 按照既有的 [branded-ids RFC](../../implemented/architecture/2026-06-20-branded-ids.md) 成为品牌化的不透明 id。 @@ -76,7 +76,7 @@ type FsWriteIntent = 该插件决定三个 `fs/*` 事件: - `fs/write-intent`——无先前观测 ⇒ `{ kind: 'createIfAbsent' }`(只有新文件可以盲创建);有先前观测 ⇒ `{ kind: 'replaceIfVersion', version: vObserved }`(已有文件仅在自观测以来未变时才替换)。单槽决策;不调用 `next()`。 -- `fs/edit-intent`——要求 owner 有先前观测(否则 `FS_NOT_OBSERVED`);返回 `{ version: vObserved }` 作为 CAS 基础。它不实现字面替换——它授权并提供版本,提供方的变更临界区负责应用守卫,因此基于同一观测版本的并发编辑仍然是一赢一过期。 +- `fs/edit-intent`——要求 owner 有先前观测(否则 `FS_NOT_OBSERVED`);返回 `{ version: vObserved }` 作为 CAS 基础。它不实现字面替换——它授权并提供版本,提供方的变更临界区负责应用守卫,因此基于同一观测版本的并发编辑仍然是一赢一陈旧。 - `fs/observed`——在成功的读取/写入/编辑后,为该 owner+target 记录 `{ version }`。同步、仅副作用的 `WeakMap.set`。 该插件不做任何文件系统 I/O:「你是否观测过此文件?」是一次 `WeakMap` 查找,而「你读取的版本是否仍然是当前版本?」在 `ctx.fs.editText`/`writeText` 内部、与执行变更相同的原子锁中决定——插件只提供 `vObserved` 作为基础。 @@ -109,7 +109,7 @@ type FsWriteIntent = ## 验证 -`dsh-fs` 精确暴露 `resolve`/`stat`/`readText`/`streamText`/`writeText`/`editText`(`stat` 返回 `FsInfo | undefined`,`writeText` 接受 `FsWriteIntent`),已删除的类型/原语不再存在;`dsh-fs-local` 不包含行、视图或 `formatReadBody` 逻辑;面向模型的 schema 保持逐字节不变。测试固定了以下行为:窗口化读取授权对未变文件的后续编辑;基于过期读取的编辑在尝试字面匹配之前报告 `FS_STALE_VERSION`;版本 CAS 行为得以保留;观测契约成立(`read` 工具的读取记录观测状态;直接 `ctx.fs` 读取不记录);`dsh-fs-policy` 具有 HMR(热模块替换)/dispose(资源释放)覆盖率。 +`dsh-fs` 精确暴露 `resolve`/`stat`/`readText`/`streamText`/`writeText`/`editText`(`stat` 返回 `FsInfo | undefined`,`writeText` 接受 `FsWriteIntent`),已删除的类型/原语不再存在;`dsh-fs-local` 不包含行、视图或 `formatReadBody` 逻辑;面向模型的 schema 保持逐字节不变。测试固定了以下行为:窗口化读取授权对未变文件的后续编辑;基于陈旧读取的编辑在尝试字面匹配之前报告 `FS_STALE_VERSION`;版本 CAS 行为得以保留;观测契约成立(`read` 工具的读取记录观测状态;直接 `ctx.fs` 读取不记录);`dsh-fs-policy` 具有 HMR(热模块替换)/dispose(资源释放)覆盖率。 ## 后续扩展 @@ -117,7 +117,7 @@ type FsWriteIntent = ## 曾考虑的替代方案 -- **字节级 fsspec(`cat`/`open` 返回原始字节)**:否决。该 seam 刻意定位为文本存储,比字节级高半个层次,这样 UTF-8 解码、二进制/NUL 拒绝和受保护的文本变更只在提供方实现一次,策略层从不接触原始字节,也不将过期检查与变更临界区分离。 +- **字节级 fsspec(`cat`/`open` 返回原始字节)**:否决。该 seam 刻意定位为文本存储,比字节级高半个层次,这样 UTF-8 解码、二进制/NUL 拒绝和受保护的文本变更只在提供方实现一次,策略层从不接触原始字节,也不将陈旧检查与变更临界区分离。 - **具体的 `ctx.fileContext` 方法服务**:本 RFC 最初的策略形态;被[事件门控 RFC](../architecture/2026-06-26-file-context-as-event-gate.md) 改造为门控插件,使工具从不与策略产生方法耦合。 - **在提供方保留 `readPage` 和 `full`/`partial` 视图授权**:「取代」一节所逆转的重构前形态。视图完整性不是编辑安全所需的,版本新鲜度才是;而视图规则使超过读取上限的大文件无法编辑。 @@ -126,5 +126,5 @@ type FsWriteIntent = - 新增第四个 fs 包和一个新的插件层。这是有意为之:它是此前推迟的策略层,而非第二个抽象后端 seam。 - 直接使用 `ctx.fs` 会绕过策略:直接 `ctx.fs.readText` 不发出 `fs/observed`,因此在默认策略下,后续 `edit` 会以 `FS_NOT_OBSERVED` 拒绝,直到通过 `read` 工具读取该文件。这一失败是显式且有文档记录的。 - 大文件行窗口化从后端移至 `dsh-tool-fs` 中的 `read` 工具;文本解码和二进制拒绝留在 `ctx.fs.streamText` 中,因此这只是窗口化逻辑的迁移,而非第二套文本 IO 实现。 -- 将 `editText` 保留在提供方 seam 上意味着每个后端都必须实现字面替换契约。这是有意为之:该操作不是纯存储,但过期守卫 + 字面匹配 + 原子重写是必须保持在一起的单元,以确保正确的错误归因和并发行为。该契约应保持窄且仅限文本,以便未来后端可以原生实现或通过全文件重写实现。 +- 将 `editText` 保留在提供方 seam 上意味着每个后端都必须实现字面替换契约。这是有意为之:该操作不是纯存储,但陈旧守卫 + 字面匹配 + 原子重写是必须保持在一起的单元,以确保正确的错误归因和并发行为。该契约应保持窄且仅限文本,以便未来后端可以原生实现或通过全文件重写实现。 - 新鲜度允许在窗口化读取后进行全文件 `write`。这比旧的视图检查更弱,但避免了大文件无法编辑的问题;提示词引导仍然不鼓励盲目的全文件替换。 diff --git a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml index a9b8b58f67..99d356c3e8 100644 --- a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-02-remove-stream-chunk-mirror.md: 1ec633b09c8e53ae7145a49061aced191a9aa765 -2026-07-02-remove-stream-chunk-mirror.zh.md: 7cf8a5d056c1bb4193263c58a8e4258173fe8b4e +2026-07-02-remove-stream-chunk-mirror.md: 74843cf49c043d46d44266a7bb0d8c953a749b6f +2026-07-02-remove-stream-chunk-mirror.zh.md: 1b460b4600442535d2572770449ce4dbcc836fe8 diff --git a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.md b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.md index 1ec633b09c..74843cf49c 100644 --- a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.md +++ b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.md @@ -1,9 +1,9 @@ # RFC: Stop mirroring the token stream as an agent event -English | [中文](2026-07-02-remove-stream-chunk-mirror.zh.md) - Status: implemented +English | [中文](2026-07-02-remove-stream-chunk-mirror.zh.md) + ## Problem The loop records every model token delta as a durable `assistant/chunk` session event AND emitted a parallel live `agent/stream-chunk` Cordis event carrying the identical data. In `packages/core/agent-loop/src/loop.ts` the two sat one line apart: diff --git a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md index 7cf8a5d056..1b460b4600 100644 --- a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md @@ -1,9 +1,9 @@ -# RFC:停止将 token 流镜像为 agent 事件 - -[English](2026-07-02-remove-stream-chunk-mirror.md) | 中文 +# RFC: 停止将 token 流镜像为 agent 事件 Status: implemented +[English](2026-07-02-remove-stream-chunk-mirror.md) | 中文 + ## 问题 agent loop(智能体循环)将模型的每个 token delta 同时记录为持久的 `assistant/chunk` 会话事件,并发射一个携带相同数据的并行实时 `agent/stream-chunk` Cordis 事件。在 `packages/core/agent-loop/src/loop.ts` 中,二者仅相隔一行: diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml index 9b195da18b..8a31f5ee11 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-04-drop-image-content-block.md: 8222880b61c225c39a1e132353c5f343fb90cb4b -2026-07-04-drop-image-content-block.zh.md: cb9372e50863193cd579c0bf8de991810db95206 +2026-07-04-drop-image-content-block.md: 145f805cbe335d3b8275bef6a2bb1fcbe1bd3df3 +2026-07-04-drop-image-content-block.zh.md: ba77caeba4cb1fdd3ff95f4cd498c87cdf1aa227 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.md b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.md index 8222880b61..145f805cbe 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.md +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.md @@ -1,9 +1,9 @@ # RFC: Drop the `image` content block until a path can honor it -English | [中文](2026-07-04-drop-image-content-block.zh.md) - Status: implemented +English | [中文](2026-07-04-drop-image-content-block.zh.md) + ## Problem `ImageBlock` (`packages/llm/llm/src/types.ts`) had no production producer, and every consumer on every path DROPPED it: the deepseek adapter's serializer skipped image blocks (a documented MVP limitation), the pi-ai converter skipped them as unrepresentable, the ACP codec neither advertises image prompt capability nor forwarded image blocks outbound and REJECTS image prompt content inbound, and the compaction estimator charged a flat token constant and rendered `[image]`. An `ImageBlock` constructed then would silently vanish from the wire — the vocabulary advertised a capability no path honored, which is the silent-data-loss shape AGENTS.md's defensive patterns warn against. The only constructors anywhere were tests pinning the skip/drop/estimate branches. diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.zh.md b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.zh.md index cb9372e508..ba77caeba4 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.zh.md @@ -1,12 +1,12 @@ -# RFC:移除 `image` 内容块,直到有路径能真正处理它 - -[English](2026-07-04-drop-image-content-block.md) | 中文 +# RFC: 移除 `image` 内容块,直到有路径能真正处理它 Status: implemented +[English](2026-07-04-drop-image-content-block.md) | 中文 + ## 问题 -`ImageBlock`(`packages/llm/llm/src/types.ts`)没有任何生产环境的生产者,而每条路径上的每个消费方都将其**丢弃**:deepseek 适配器的序列化器跳过 image 块(这是文档中注明的 MVP 限制);pi-ai 转换器因无法表示而跳过;ACP 编解码器既不宣告 image prompt 能力、也不向外转发 image 块,并且会拒绝入站的 image prompt 内容;压缩(compaction)估算器对其收取一个固定 token 常量并渲染为 `[image]`。此时构造的 `ImageBlock` 会在协议格式(wire format)上静默消失——词汇宣告了一种没有任何路径兑现的能力,这正是 AGENTS.md 防御性模式所警告的静默数据丢失形态。唯一的构造调用出现在测试中,用于覆盖 skip/drop/estimate 分支。 +`ImageBlock`(`packages/llm/llm/src/types.ts`)没有任何生产环境的生产者,而每条路径上的每个消费方都将其丢弃:deepseek 适配器的序列化器跳过 image 块(这是文档中注明的 MVP 限制);pi-ai 转换器因无法表示而跳过;ACP 编解码器既不宣告 image prompt 能力、也不向外转发 image 块,并且会拒绝入站的 image prompt 内容;压缩(compaction)估算器对其收取一个固定 token 常量并渲染为 `[image]`。此时构造的 `ImageBlock` 会在协议格式(wire format)上静默消失——词汇宣告了一种没有任何路径兑现的能力,这正是 AGENTS.md 防御性模式所警告的静默数据丢失形态。唯一的构造调用出现在测试中,用于覆盖 skip/drop/estimate 分支。 ## 决策 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml index 3dabffc3a4..429e5ae268 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-04-drop-inert-request-knobs.md: d5484aa5ec64f89ce705ddd0a434c2c4dfbad460 -2026-07-04-drop-inert-request-knobs.zh.md: 9bd13cd024bc0e2ba7795a190d77063c3457fe98 +2026-07-04-drop-inert-request-knobs.md: 86d0dfefe1bdfb0c49b5b9080935441d16dd2223 +2026-07-04-drop-inert-request-knobs.zh.md: f7d969378af7e070ecee82e8ea1a569c61208208 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.md b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.md index d5484aa5ec..86d0dfefe1 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.md +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.md @@ -1,9 +1,9 @@ # RFC: Drop `GenerateOptions.prefill` and `ToolSchema.strict` — request knobs with no working end-to-end path -English | [中文](2026-07-04-drop-inert-request-knobs.zh.md) - Status: implemented +English | [中文](2026-07-04-drop-inert-request-knobs.zh.md) + ## Problem Two request-contract knobs rode the whole request pipeline, yet neither could do anything: diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md index 9bd13cd024..f7d969378a 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md @@ -1,14 +1,14 @@ -# RFC:移除 `GenerateOptions.prefill` 与 `ToolSchema.strict`——无端到端可用路径的请求旋钮 - -[English](2026-07-04-drop-inert-request-knobs.md) | 中文 +# RFC: 移除 `GenerateOptions.prefill` 与 `ToolSchema.strict`——无端到端可用路径的请求旋钮 Status: implemented +[English](2026-07-04-drop-inert-request-knobs.md) | 中文 + ## 问题 两个请求契约旋钮贯穿了整条请求流水线,却都无法产生任何效果: -- **`prefill`**(`packages/llm/llm/src/types.ts`)没有生产级的 setter:agent loop(智能体循环)组装的是 `model`/`system`/`tools`/`messages` 加 `sessionId`/`signal`,上下文压缩(context compaction)后端只追加 `maxTokens`;而且**两个**适配器都拒绝它:`packages/llm/llm-deepseek/src/serialize.ts` 和 `packages/llm/llm-pi-ai/src/adapter.ts` 各自在 `prefill` 非 undefined 时抛出 `LlmError('UNSUPPORTED')`。该字段的全部可观测行为就是两个 throw,各由一条适配器测试固定。DeepSeek 的 chat-prefix completion 是一个 Beta 功能,运行在两个适配器都未指向的 base URL 上。 +- **`prefill`**(`packages/llm/llm/src/types.ts`)没有生产级的 setter:agent loop(智能体循环)组装的是 `model`/`system`/`tools`/`messages` 加 `sessionId`/`signal`,上下文压缩(context compaction)后端只追加 `maxTokens`;而且两个适配器都拒绝它:`packages/llm/llm-deepseek/src/serialize.ts` 和 `packages/llm/llm-pi-ai/src/adapter.ts` 各自在 `prefill` 非 undefined 时抛出 `LlmError('UNSUPPORTED')`。该字段的全部可观测行为就是两个 throw,各由一条适配器测试固定。DeepSeek 的 chat-prefix completion 是一个 Beta 功能,运行在两个适配器都未指向的 base URL 上。 - **`strict`**(`ToolSchema`,同一文件)穿过了 `DefineToolOptions`/`defineTool`(`packages/core/tools/src/schema.ts`)、注册表的 `schemas()` 允许列表(`packages/core/tools/src/index.ts`)、deepseek 协议格式(wire format)映射(`packages/llm/llm-deepseek/src/serialize.ts`,其 wire-type 注释记录了 strict 模式需要适配器未使用的 `/beta` base URL)、`packages/llm/llm-pi-ai/src/adapter.ts` 中的逐工具 payload 修补逻辑,以及 tool-catalog 渲染器(`scripts/gen-tool-catalog.ts`)中的条件 `Strict:` 行。没有任何已发布的工具设置过它——在所有 `tool-*` 包的 src 和 `examples/` 中执行 `rg` 搜索,`strict:` 的生产者为零;唯一的 setter 出现在 dsh-tools 单元测试中。 两个旋钮在适配器间是对称的,因此移除操作将它们从两个孪生适配器中一并剥离——[孪生适配器设计](../architecture/2026-06-13-twin-llm-adapters.md)不受影响。 @@ -18,13 +18,13 @@ Status: implemented - 从 `GenerateOptions` 中移除 `prefill`,同时移除两个适配器的 UNSUPPORTED 守卫、固定这些 throw 的测试、[core.md](../../../core-data-structures/core.md) 中的粘贴行,以及适配器 README 中记录拒绝行为的行。实操手册(cookbook)中的 UNSUPPORTED 指引([adding-an-llm-adapter.md](../../../cookbook/adding-an-llm-adapter.md))改为泛化表述——你的 provider 无法兑现的 `GenerateOptions` 字段应抛出 `LlmError(..., 'UNSUPPORTED')`——而不再以 prefill 为例。[内容块词汇 RFC](../architecture/2026-06-11-content-block-vocabulary.md) 的后果部分将 prefill 记录为「受 producer 门控」而非「已有归属」,依据 [implemented/AGENTS.md](../AGENTS.md)。 - 从 `ToolSchema`、`DefineToolOptions`、`defineTool`、`schemas()` 允许列表、deepseek 序列化分支及其 wire-type 字段,以及 tool-catalog 渲染器的 `Strict:` 行中移除 `strict`。pi-ai 的 payload 修补逻辑简化为对 pi-ai 自身逐工具 strict 默认值的无条件清除(pi-ai 在每个序列化的工具上打 `strict: false`;手写的孪生适配器不发送此字段,因此清除逻辑为保持协议格式对等而保留,由其序列化器测试固定)。setter 测试和 core.md 粘贴行已移除;`GenerateOptions` 与 `ToolSchema` 在 `scripts/type-equiv.manifest.json` 中保留各自的行,因为两个类型只是少了一个字段,本身仍然存在。 -本 RFC 有意**不**触碰 `temperature`、`stop` 或 `maxTokens`:它们在两个适配器中都被端到端地兑现,是 `agent/request` 上请求变更钩子插件的自然首选目标。 +本 RFC 有意不触碰 `temperature`、`stop` 或 `maxTokens`:它们在两个适配器中都被端到端地兑现,是 `agent/request` 上请求变更钩子插件的自然首选目标。 ## 曾考虑的替代方案 ### 为什么不保留? -「显式的 UNSUPPORTED throw 是诚实的契约行为」——但一个在两个孪生适配器中唯一的实现就是拒绝的旋钮,什么也没承诺;删除它反而升级了失败模式:意外的 setter 变成编译错误而非运行时 throw。「Strict schema 遵循是官方文档记载的 provider 功能,且管道完整」——但一个旋钮在有已发布的工具设置它**并且**有端点兑现它之前,不构成产品表面;今天两者都不成立。它们各自随首个真实 producer 回归:`prefill` 随实现了 chat-prefix completion 的适配器(以及对不支持该功能的适配器的明确策略)一起回来;`strict` 随需要它的工具和 beta 端点方案一起回来。 +「显式的 UNSUPPORTED throw 是诚实的契约行为」——但一个在两个孪生适配器中唯一的实现就是拒绝的旋钮,什么也没承诺;删除它反而升级了失败模式:意外的 setter 变成编译错误而非运行时 throw。「Strict schema 遵循是官方文档记载的 provider 功能,且管道完整」——但一个旋钮在有已发布的工具设置它并且有端点兑现它之前,不构成产品表面;今天两者都不成立。它们各自随首个真实 producer 回归:`prefill` 随实现了 chat-prefix completion 的适配器(以及对不支持该功能的适配器的明确策略)一起回来;`strict` 随需要它的工具和 beta 端点方案一起回来。 ## 验证 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml index fb1161ae18..d86354d68a 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-04-drop-unconsumed-web-observation-surface.md: c48ff5b80c916cd6cc04d6a8339a8555d05b0d40 -2026-07-04-drop-unconsumed-web-observation-surface.zh.md: 4988a5aa77604f528cc23409a3c2290c890a7f5a +2026-07-04-drop-unconsumed-web-observation-surface.md: ba97076eef385cd218517f233ed44f86d3f7eb7a +2026-07-04-drop-unconsumed-web-observation-surface.zh.md: 83c2e786d4edde7b7c94cf2c028b14e20da842b4 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.md b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.md index c48ff5b80c..ba97076eef 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.md +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.md @@ -1,9 +1,9 @@ # RFC: Drop the unconsumed web observation surface — the `providers-change` event and the status methods -English | [中文](2026-07-04-drop-unconsumed-web-observation-surface.zh.md) - Status: implemented +English | [中文](2026-07-04-drop-unconsumed-web-observation-surface.zh.md) + ## Problem `WebService` exposes an observation surface no production code observes: diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md index 4988a5aa77..83c2e786d4 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md @@ -1,4 +1,4 @@ -# RFC:移除未被消费的 web 观测接口——`providers-change` 事件与 status 方法 +# RFC: 移除未被消费的 web 观测接口——`providers-change` 事件与 status 方法 Status: implemented @@ -23,7 +23,7 @@ seam 自身的设计使这两个接口天然没有消费方:工具注册跟随 ### 为什么不保留? -web seam RFC 有意指定了两者——事件作为最小的 HMR 可见性信号,status 方法作为工具的聚合诊断——且未来的 provider 状态面板是可以想象的。但同一 RFC 的其他设计选择使它们失去了消费方:按需派生的选择与基于 enablement 的注册使得没有消费方**能**需要这两者;已交付的工具展示了真实模式(执行并路由结构化错误);漂移的 README 语句表明承诺的消费方从未实现。按 AGENTS.md「RFC 是提案,不是金科玉律」的原则,这些是该提案中代码已证明过度设计的部分;未来的观测者按其实际消费的需求重新引入最小的信号或查询,由该消费方塑造其形态。 +web seam RFC 有意指定了两者——事件作为最小的 HMR 可见性信号,status 方法作为工具的聚合诊断——且未来的 provider 状态面板是可以想象的。但同一 RFC 的其他设计选择使它们失去了消费方:按需派生的选择与基于 enablement 的注册使得没有消费方能需要这两者;已交付的工具展示了真实模式(执行并路由结构化错误);漂移的 README 语句表明承诺的消费方从未实现。按 AGENTS.md「RFC 是提案,不是金科玉律」的原则,这些是该提案中代码已证明过度设计的部分;未来的观测者按其实际消费的需求重新引入最小的信号或查询,由该消费方塑造其形态。 ## 验证 diff --git a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml index 4ca47feeee..a43d663e93 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-04-fold-stdio-ui-helper.md: 8d26af190a957b424960519f77cbe132291c74de -2026-07-04-fold-stdio-ui-helper.zh.md: 795edf082258a56d3c11afbbb8de8cfa0e74e74e +2026-07-04-fold-stdio-ui-helper.md: ab42f1d131f6c657edf078d953c646b7970e9782 +2026-07-04-fold-stdio-ui-helper.zh.md: 2ad6abf3d5fb5ae6cdd852f8b5ec7e061e62b8ed diff --git a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md index 8d26af190a..ab42f1d131 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md +++ b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md @@ -1,9 +1,9 @@ # RFC: Fold the stdio UI helper into the stdio app -English | [中文](2026-07-04-fold-stdio-ui-helper.zh.md) - Status: implemented +English | [中文](2026-07-04-fold-stdio-ui-helper.zh.md) + ## Problem The readline UI was a whole package (`@deepseek-ai/dsh-ui-stdio` under `packages/support/`) whose only runtime importer was the app package `@deepseek-ai/dsh-stdio-demo`. The examples reach the readline UI by loading the app, never by composing the helper themselves; every other repo reference was mechanical or descriptive surface that existed BECAUSE the package boundary existed — manifest and tsconfig entries, generated module-graph rows, dependency-graph and README rows, and doc comments naming the package. The ui group README recorded the support placement rationale ("exists chiefly for the examples and the coverage gate — `ui/` is reserved for surfaces shipped as product"), which left a standing tension: a shipped product app depending on a support package documented as NOT product surface. diff --git a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md index 795edf0822..2ad6abf3d5 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md @@ -1,9 +1,9 @@ -# RFC:将 stdio UI 辅助模块折入 stdio 应用 - -[English](2026-07-04-fold-stdio-ui-helper.md) | 中文 +# RFC: 将 stdio UI 辅助模块折入 stdio 应用 Status: implemented +[English](2026-07-04-fold-stdio-ui-helper.md) | 中文 + ## 问题 readline UI 曾是一个完整的包(`packages/support/` 下的 `@deepseek-ai/dsh-ui-stdio`),其唯一的运行时导入方是应用包 `@deepseek-ai/dsh-stdio-demo`。示例通过加载应用来使用 readline UI,从不自行组合该辅助模块;仓库中所有其他引用都是因为包边界存在而存在的机械性或描述性表面:manifest(元数据清单)与 tsconfig 条目、生成的 module-graph 行、依赖图与 README 行,以及命名该包的文档注释。ui 组 README 记录了 support 放置的理由("主要为示例和覆盖率门禁而存在,`ui/` 保留给作为产品交付的界面"),这留下了一个持续的张力:一个已交付的产品应用依赖一个被明确标注为非产品表面的 support 包。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml index ef7e3c8092..1d12fb892b 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-04-prune-producerless-vocabulary-variants.md: 271b97f6217a2694f36b7fe7339eab6176dba9e5 -2026-07-04-prune-producerless-vocabulary-variants.zh.md: 2fe8d41a011c37919bd01022d5be6d309b865bf7 +2026-07-04-prune-producerless-vocabulary-variants.md: f1b80e35b9004e40fb0ffdd08310310848912d09 +2026-07-04-prune-producerless-vocabulary-variants.zh.md: 9e7b55256ba5bda0474fd9056eea9a96beaf8096 diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md index 271b97f621..f1b80e35b9 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md @@ -1,9 +1,9 @@ # RFC: Prune producer-less vocabulary variants (block cache hints, the `agent` message source, the `continuation` turn trigger) -English | [中文](2026-07-04-prune-producerless-vocabulary-variants.zh.md) - Status: implemented +English | [中文](2026-07-04-prune-producerless-vocabulary-variants.zh.md) + ## Problem The merge-extensible vocabulary maps are designed to grow by declaration merging, and the codebase already states the admission policy on `TurnEndReasonMap` (`packages/core/session/src/types.ts`): a variant like `refusal` is "deliberately omitted until" an adapter or loop first emits it. Three declared vocabulary items violated that policy — each had no producer and no consumer, and two had not even a test: diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md index 2fe8d41a01..9e7b55256b 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md @@ -1,9 +1,9 @@ -# RFC:裁剪无生产者的词汇变体(块缓存提示、`agent` 消息来源、`continuation` 轮次触发器) - -[English](2026-07-04-prune-producerless-vocabulary-variants.md) | 中文 +# RFC: 裁剪无生产者的词汇变体(块缓存提示、`agent` 消息来源、`continuation` 轮次触发器) Status: implemented +[English](2026-07-04-prune-producerless-vocabulary-variants.md) | 中文 + ## 问题 可合并扩展的词汇映射表设计上通过声明合并来增长,代码库已在 `TurnEndReasonMap`(`packages/core/session/src/types.ts`)上明确了准入策略:像 `refusal` 这样的变体「在适配器或循环首次发出它之前,有意不纳入」。三个已声明的词汇项违反了该策略——每个都既无生产者也无消费方,其中两个甚至没有测试: diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml index 428dfb9379..a595aef18a 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-04-prune-write-only-fs-surface.md: ac2cbcc282b848b26a3d5d327e0ab54612b5ac91 -2026-07-04-prune-write-only-fs-surface.zh.md: e854df76cae74033404aa9cc1986fdd118f19b10 +2026-07-04-prune-write-only-fs-surface.md: f41619ecde1bbf2a1d6d8f8d769409f624fc22c7 +2026-07-04-prune-write-only-fs-surface.zh.md: afcf1aad28db056997930162539a57bb08bbe815 diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.md b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.md index ac2cbcc282..f41619ecde 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.md +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.md @@ -1,9 +1,9 @@ # RFC: Prune write-only fields and a dead routing knob from the fs seam -English | [中文](2026-07-04-prune-write-only-fs-surface.zh.md) - Status: implemented +English | [中文](2026-07-04-prune-write-only-fs-surface.zh.md) + ## Problem The [fs seam split](2026-06-26-fsspec-style-fs-seam.md) moved read routing and policy out of the backend into `dsh-tool-fs` and `dsh-fs-policy`. Four pieces of surface kept the pre-split shape — populated on every call, read by nobody: diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md index e854df76ca..afcf1aad28 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md @@ -1,9 +1,9 @@ -# RFC:从 fs seam 中移除只写字段与一个无效的路由旋钮 - -[English](2026-07-04-prune-write-only-fs-surface.md) | 中文 +# RFC: 从 fs seam 中移除只写字段与一个无效的路由旋钮 Status: implemented +[English](2026-07-04-prune-write-only-fs-surface.md) | 中文 + ## 问题 [fs seam 拆分](2026-06-26-fsspec-style-fs-seam.md)将读取路由与策略从后端移至 `dsh-tool-fs` 和 `dsh-fs-policy`。有四处接口保留了拆分前的形态——每次调用都填充,却无人读取: diff --git a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml index be2b32be56..ca0bd62294 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-04-remove-agent-steering-mirror.md: 311f0f8ffd278adf71a35617b900d4d16037055a -2026-07-04-remove-agent-steering-mirror.zh.md: 24198afb0714863867f4d7e17ae19ea8af6a88bd +2026-07-04-remove-agent-steering-mirror.md: fbd13b3d43b0052bcdeffd7f94caa341e1f636c5 +2026-07-04-remove-agent-steering-mirror.zh.md: 185cc5601a7406e0d801afd877e9d97eaaa12a0c diff --git a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.md b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.md index 311f0f8ffd..fbd13b3d43 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.md +++ b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.md @@ -1,9 +1,9 @@ # RFC: Remove the `agent/steering` mirror emit -English | [中文](2026-07-04-remove-agent-steering-mirror.zh.md) - Status: implemented +English | [中文](2026-07-04-remove-agent-steering-mirror.zh.md) + ## Problem `agent/steering` was the last remaining transient mirror of a durable session event. The loop's steering drain appends the durable `steering/message { turn, content, source }` and, on the very next line, emitted `agent/steering(agent, turn, content, source)` — the identical fact as a fire-and-forget event (`packages/core/agent-loop/src/loop.ts`, `drainSteering`). It had zero production listeners: the only subscriber anywhere was a loop regression test asserting the emit carried `source` — the same fact the durable event already records one line above. diff --git a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md index 24198afb07..185cc5601a 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md @@ -1,9 +1,9 @@ -# RFC:移除 `agent/steering` 镜像 emit - -[English](2026-07-04-remove-agent-steering-mirror.md) | 中文 +# RFC: 移除 `agent/steering` 镜像 emit Status: implemented +[English](2026-07-04-remove-agent-steering-mirror.md) | 中文 + ## 问题 `agent/steering` 是最后一个仍存在的、对持久会话事件的瞬态镜像。agent loop(智能体循环)的 steering(中途引导)drain 逻辑先追加持久事件 `steering/message { turn, content, source }`,紧接着下一行就 emit `agent/steering(agent, turn, content, source)`——同一个事实以 fire-and-forget 事件的形式重复发出(`packages/core/agent-loop/src/loop.ts`,`drainSteering`)。它在生产环境中没有任何监听者:唯一的订阅方是一个 agent loop 回归测试,断言 emit 携带了 `source`——而这同一个事实已经由上一行的持久事件记录。 @@ -22,7 +22,7 @@ steering 承载着真实的生产流量:hook bridge 的轮次续行决策通 ### 为什么不保留? -"它是控制信号,不是边界事件"——但分类体系的操作性区分是「镜像 vs. 纯瞬态」,而非「控制 vs. 边界」,而这个事件属于镜像。需要入队时通知的消费方有 `agent/queued`(带 steering flag);需要 drain 时通知的消费方,本质上是在请求 `steering/message` 被追加的那一刻,而 `session/event` 以相同 payload 加上持久性提供了这一通知。被否决的 [retire-mid-turn-steering RFC](../../rejected/simplification/2026-06-20-retire-mid-turn-steering.md) 捍卫的是 steering **能力**——`steer()`、持久事件、续行强制——本次移除对这些全部保持不变。 +"它是控制信号,不是边界事件"——但分类体系的操作性区分是「镜像 vs. 纯瞬态」,而非「控制 vs. 边界」,而这个事件属于镜像。需要入队时通知的消费方有 `agent/queued`(带 steering flag);需要 drain 时通知的消费方,本质上是在请求 `steering/message` 被追加的那一刻,而 `session/event` 以相同 payload 加上持久性提供了这一通知。被否决的 [retire-mid-turn-steering RFC](../../rejected/simplification/2026-06-20-retire-mid-turn-steering.md) 捍卫的是 steering *能力*——`steer()`、持久事件、续行强制——本次移除对这些全部保持不变。 ## 验证 diff --git a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml index 6a470484f3..788e1735b5 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-04-share-app-bin-boot-glue.md: afaa61fe909f3dbf900337518969410780020a88 -2026-07-04-share-app-bin-boot-glue.zh.md: 33fe2f27df9c8b172e4296ece0720813f9775f86 +2026-07-04-share-app-bin-boot-glue.md: 31666e74bb0bb0086de85e6a3afafbc2f73a6e52 +2026-07-04-share-app-bin-boot-glue.zh.md: d18f83be0f76774e39a1e54f1ea2db3c1c1b7688 diff --git a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.md b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.md index afaa61fe90..31666e74bb 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.md +++ b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.md @@ -1,9 +1,9 @@ # RFC: Share the app bins' boot glue instead of maintaining twin copies -English | [中文](2026-07-04-share-app-bin-boot-glue.zh.md) - Status: implemented +English | [中文](2026-07-04-share-app-bin-boot-glue.zh.md) + ## Problem The stdio and ACP bins duplicated environment loading, fail-loud handling, entry validation, and boot logic, including subtle Loader failure behavior. Their copies had already drifted and lived in self-executing files excluded from unit coverage, making their helper exports unusable. diff --git a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md index 33fe2f27df..d18f83be0f 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md @@ -1,9 +1,9 @@ -# RFC:共享应用 bin 的启动胶水代码,而非维护两份副本 - -[English](2026-07-04-share-app-bin-boot-glue.md) | 中文 +# RFC: 共享应用 bin 的启动胶水代码,而非维护两份副本 Status: implemented +[English](2026-07-04-share-app-bin-boot-glue.md) | 中文 + ## 问题 stdio 和 ACP 两个 bin 各自重复了环境加载、fail-loud 处理、入口校验与启动逻辑,包括微妙的 Loader 失败行为。两份副本已经发生漂移,且位于自执行文件中、被排除在单元测试覆盖率之外,导致其导出的辅助函数无法被复用。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml index 95c2fdbf50..b2926299df 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-04-tighten-hook-protocol-contract.md: df438516b836315902378afe7f4fd09e512c0966 -2026-07-04-tighten-hook-protocol-contract.zh.md: 256da42993c8581e8bce861ecbfac22dbf5f0545 +2026-07-04-tighten-hook-protocol-contract.md: 92ed629edaa0364d88955458f39f6280322e79c7 +2026-07-04-tighten-hook-protocol-contract.zh.md: 9b5b19d7ad522fdf74eb330c259d8dee03bee604 diff --git a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.md b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.md index df438516b8..92ed629eda 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.md +++ b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.md @@ -1,9 +1,9 @@ # RFC: Tighten the hook-protocol contract — dialect, discarded fields, double defaults, and lib-owned `hook/result` semantics -English | [中文](2026-07-04-tighten-hook-protocol-contract.zh.md) - Status: implemented +English | [中文](2026-07-04-tighten-hook-protocol-contract.zh.md) + ## Problem Four pieces of the `dsh-hook-protocol`/bridge contract missed the discipline the [subagent-observe-enrich RFC](../feature/2026-06-30-subagent-observe-enrich.md) records — it dropped an `agentType` lifecycle field for lacking a consumer, and these failed the same test: diff --git a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md index 256da42993..9b5b19d7ad 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md @@ -1,9 +1,9 @@ -# RFC:收紧 hook-protocol 契约——dialect、废弃字段、双重默认值与 lib 拥有的 `hook/result` 语义 - -[English](2026-07-04-tighten-hook-protocol-contract.md) | 中文 +# RFC: 收紧 hook-protocol 契约——dialect、废弃字段、双重默认值与 lib 拥有的 `hook/result` 语义 Status: implemented +[English](2026-07-04-tighten-hook-protocol-contract.md) | 中文 + ## 问题 `dsh-hook-protocol`/bridge 契约中有四处遗漏了 [subagent-observe-enrich RFC](../feature/2026-06-30-subagent-observe-enrich.md) 所记录的纪律——该 RFC 因缺乏消费方而移除了 `agentType` 生命周期字段,以下四处未通过同样的检验: diff --git a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml index aa5df52a6a..f0afae419b 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-04-trim-acp-bridge-unreachable-surface.md: 6decb494dcbfd348777577002187007597a8c374 -2026-07-04-trim-acp-bridge-unreachable-surface.zh.md: 9d588e6f1132869ead60586b4df6844400307863 +2026-07-04-trim-acp-bridge-unreachable-surface.md: 05a62c92ec1553e6eb0b14adc86f8aa1b89827e5 +2026-07-04-trim-acp-bridge-unreachable-surface.zh.md: 851198eee0559013429ef4eb5491cd7f97217c46 diff --git a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md index 6decb494dc..05a62c92ec 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md +++ b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md @@ -1,9 +1,9 @@ # RFC: Trim unreachable ACP bridge surface — the branding knobs and the kind-sniffing fallback -English | [中文](2026-07-04-trim-acp-bridge-unreachable-surface.zh.md) - Status: implemented +English | [中文](2026-07-04-trim-acp-bridge-unreachable-surface.zh.md) + ## Problem Two pieces of `dsh-acp` surface were unreachable from any shipped configuration: diff --git a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md index 9d588e6f11..851198eee0 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md @@ -1,9 +1,9 @@ -# RFC:裁剪不可达的 ACP 桥接层表面——品牌配置项与 kind 嗅探回退 - -[English](2026-07-04-trim-acp-bridge-unreachable-surface.md) | 中文 +# RFC: 裁剪不可达的 ACP 桥接层表面——品牌配置项与 kind 嗅探回退 Status: implemented +[English](2026-07-04-trim-acp-bridge-unreachable-surface.md) | 中文 + ## 问题 `dsh-acp` 有两处对外表面在任何已交付的配置中都不可达: diff --git a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml index 593cb8a50e..3644236c38 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-12-drop-unconsumed-skill-provider-events.md: 5ec9d201939b8f58334647353f599361bd2e58a0 -2026-07-12-drop-unconsumed-skill-provider-events.zh.md: 15dbfedb07afa36b677074c403812d0f164c8bd5 +2026-07-12-drop-unconsumed-skill-provider-events.md: 90157c03e5df05c98b992ce1dbefea26f4865ce7 +2026-07-12-drop-unconsumed-skill-provider-events.zh.md: 19fec4b827b89b4127b749a9c77715baf39dd00a diff --git a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.md b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.md index 5ec9d20193..90157c03e5 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.md +++ b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.md @@ -1,9 +1,9 @@ # RFC: Drop unconsumed skill provider events -English | [中文](2026-07-12-drop-unconsumed-skill-provider-events.zh.md) - Status: implemented +English | [中文](2026-07-12-drop-unconsumed-skill-provider-events.zh.md) + ## Problem Two skill-registry notifications are produced but have no production listener. The generated producer/consumer matrix and exact event-name searches find only declarations, emit sites, tests, generated catalogs, and prose for `skill/provider-added` and `skill/provider-removed`. diff --git a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md index 15dbfedb07..19fec4b827 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md @@ -1,9 +1,9 @@ -# RFC:移除无消费方的 skill 提供方事件 - -[English](2026-07-12-drop-unconsumed-skill-provider-events.md) | 中文 +# RFC: 移除无消费方的 skill 提供方事件 Status: implemented +[English](2026-07-12-drop-unconsumed-skill-provider-events.md) | 中文 + ## 问题 skill(技能)注册表产出两个通知事件,但没有生产环境的监听方。生成的生产者/消费方矩阵以及对事件名的精确搜索表明,`skill/provider-added` 与 `skill/provider-removed` 仅出现在声明、emit 站点、测试、生成的 catalog 和行文中。 diff --git a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml index 7413576228..703539b152 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-12-prune-unused-web-seam-fields.md: b4773c2706cf6d18ea4bb96720cd6c932cdf8942 -2026-07-12-prune-unused-web-seam-fields.zh.md: 2c18fbcb440ce85798c8f36cdc5dc649149d8ba9 +2026-07-12-prune-unused-web-seam-fields.md: 9fd05da282c22d78dc98e232ef2c23cd6e9c4ea3 +2026-07-12-prune-unused-web-seam-fields.zh.md: 650b6b74c808c719bcea9783c60064936427ffee diff --git a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.md b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.md index b4773c2706..9fd05da282 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.md +++ b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.md @@ -1,9 +1,9 @@ # RFC: Prune unused web seam fields -English | [中文](2026-07-12-prune-unused-web-seam-fields.zh.md) - Status: implemented +English | [中文](2026-07-12-prune-unused-web-seam-fields.zh.md) + ## Problem The web capability carries request/result/status values that every shipped implementation populates but no production consumer reads. `WebSearchResult.providerId` and `query` and `WebFetchResult.providerId` are result echoes; `tool-web` formats only content/sources/truncation or final URL/status/body/truncation, and no other runtime reads them. Search providers return `WebProviderStatus.reason`, but resolution checks only `available` and intentionally emits a generic unavailable diagnostic. diff --git a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md index 2c18fbcb44..650b6b74c8 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md @@ -1,9 +1,9 @@ -# RFC:裁剪 web seam 中未使用的字段 - -[English](2026-07-12-prune-unused-web-seam-fields.md) | 中文 +# RFC: 裁剪 web seam 中未使用的字段 Status: implemented +[English](2026-07-12-prune-unused-web-seam-fields.md) | 中文 + ## 问题 web 能力携带的 request/result/status 值,虽然每个已交付的实现都会填充,但没有任何生产环境的消费方读取它们。`WebSearchResult.providerId`、`query`与 `WebFetchResult.providerId` 是结果回显;`tool-web` 只格式化 content/sources/truncation 或最终 URL/status/body/truncation,没有其他运行时读取这些字段。搜索提供方返回 `WebProviderStatus.reason`,但可用性检查只看 `available`,并有意输出一条通用的不可用诊断信息。 diff --git a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.i18n.yaml b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.i18n.yaml index cc2bf1f23f..22d74d7424 100644 --- a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-property-based-testing.md: 169989746ea5114b1f35e7ebe35a02e8aeb0f782 -2026-06-11-property-based-testing.zh.md: 4f2303010f44279c4edd0ec5a509b71f8aad606b +2026-06-11-property-based-testing.md: 153584d3a2b77c8f2d103db02646f18a9d424b57 +2026-06-11-property-based-testing.zh.md: e11d11f7db9eee97ab81bc678afab5d0fea36bf9 diff --git a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.md b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.md index 169989746e..153584d3a2 100644 --- a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.md +++ b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.md @@ -1,9 +1,9 @@ # RFC: Property-based testing for protocol-shaped code -English | [中文](2026-06-11-property-based-testing.zh.md) - Status: implemented +English | [中文](2026-06-11-property-based-testing.zh.md) + > Merges the original proposal and the decision record for one topic. It found a real BlockAssembler duplicate-`block-end` bug on first run. ## Problem diff --git a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.zh.md b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.zh.md index 4f2303010f..e11d11f7db 100644 --- a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.zh.md +++ b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.zh.md @@ -1,4 +1,4 @@ -# RFC:对协议形态代码进行基于属性的测试 +# RFC: 对协议形态代码进行基于属性的测试 Status: implemented @@ -14,7 +14,7 @@ Status: implemented 引入 `fast-check`(作为根 devDependency),在每个协议形态的包(package)中编写一个 `tests/properties.spec.ts`。生成器调优为*逼真但对抗性*的输入(而非均匀噪声),`numRuns` 控制在本地套件总耗时远低于约 10 秒。失败时打印可复现的 seed。(原始提案还草拟了一个夜间 CI job,以 100 倍迭代运行;该部分未交付。属性测试套件仅在常规的 `push`/`pull_request` CI 中运行,定时高迭代 job 仍属可能的后续工作。) -- **dsh-llm / BlockAssembler:** 任意分片流(合法 + 畸形:重复索引、滞后分片、缺少 block-start)。不变式:`blocks()` 计数 ≤ 已见到的不同索引数;重组幂等(`blocks()` 在重复调用间稳定,且 `message().content` 与之一致);`blocks()` 从不抛异常且仅产出合法的 content-block 标签;`finish` 反映最后一个 `finish` 分片,无 `finish` 分片时默认为 `{kind:'stop'}`。 +- **dsh-llm / BlockAssembler:** 任意分片流(合法 + 畸形:重复索引、滞后分片、缺少 block-start)。不变式:`blocks()` 计数 ≤ 已见到的不同索引数;重组幂等(`blocks()` 在重复调用间稳定,且 `message().content` 与之一致);`blocks()` 从不抛异常且仅产出合法的 content-block 标签;`finish` 反映最后一个 `finish` 分片,无此类分片时默认为 `{kind:'stop'}`。 - **dsh-session:** 任意事件日志。不变式:`deriveMessages` 确定性;从 seed 回放结果一致;seq 严格单调递增;非消息事件不影响推导出的历史;推导出的内容与日志解耦。 - **dsh-tools:** 任意 `SchemaSpec`。不变式:JSON Schema 的 `required` 等于每一层 `required:true` 的键集;转换是全函数;**并且与[运行时参数校验](../architecture/2026-06-11-runtime-arg-validation.md)组合验证**——满足 spec 的生成参数通过 `validateArgs`,而定向破坏(删除必填键、顶层非对象)被拒绝。这封堵了 validator 与 `InferArgs` 漂移的风险。 - **dsh-agent-loop:** 任意发送调度,对接一个永不耗尽的适配器,通过 `agent/status` settle 信号驱动(无挂钟 sleep)。不变式:无消息丢失;轮次编号严格递增;状态转换保持在合法状态机上。 diff --git a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml index 1dfb26a628..10573d8e31 100644 --- a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-19-acp-snapshot-tests.md: 0b93c99932a33bca9945dd88ce45f4a1e100ccfc -2026-06-19-acp-snapshot-tests.zh.md: 26c583ba47b8ec10ab3d0e2102a8b791549fda38 +2026-06-19-acp-snapshot-tests.md: c336b4864b73b8db29c0a8bb983d974348a9515a +2026-06-19-acp-snapshot-tests.zh.md: bc9488562b0698b172ccffff74815a893acf722d diff --git a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md index 0b93c99932..c336b4864b 100644 --- a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md +++ b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md @@ -1,9 +1,9 @@ # RFC: ACP snapshot tests — record-once / replay-deterministic -English | [中文](2026-06-19-acp-snapshot-tests.zh.md) - Status: implemented +English | [中文](2026-06-19-acp-snapshot-tests.zh.md) + ## Problem Unit tests do not exercise the complete ACP subprocess transcript, while real-API tests are nondeterministic and key-gated. Editor-facing `session/update` output can therefore regress despite green unit coverage, as the [default-export postmortem](../../../postmortem/0001-acp-default-export-drops-inject.md) demonstrated. diff --git a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md index 26c583ba47..bc9488562b 100644 --- a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md +++ b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md @@ -1,4 +1,4 @@ -# RFC:ACP 快照测试——一次录制 / 确定性回放 +# RFC: ACP 快照测试——一次录制 / 确定性回放 Status: implemented diff --git a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml index 591f51750a..bb98e02fd7 100644 --- a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-19-real-api-e2e-ci.md: 3b5995a3e060ef9b4b1639b5c7fb17c819e73150 -2026-06-19-real-api-e2e-ci.zh.md: 78bab7c1e00125bfbe11b8f08eeeff3f2b7723b1 +2026-06-19-real-api-e2e-ci.md: cc3e14e2d411dfa4cc68132f649f4ed26ab1de1d +2026-06-19-real-api-e2e-ci.zh.md: 58a2a87541fd5b73b8272aa729f9dd09a429e4b4 diff --git a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.md b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.md index 3b5995a3e0..cc3e14e2d4 100644 --- a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.md +++ b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.md @@ -1,9 +1,9 @@ # RFC: Real-API e2e in CI against the external DeepSeek API -English | [中文](2026-06-19-real-api-e2e-ci.zh.md) - Status: implemented +English | [中文](2026-06-19-real-api-e2e-ci.zh.md) + ## Problem The harness leans hard on real-API tests by policy: [docs/testing.md](../../../testing.md) argues that a no-key suite proves the plumbing but not the product, and the [ACP inject postmortem](../../../postmortem/0001-acp-default-export-drops-inject.md) is the standing proof — 178 keyless tests stayed green while a real editor session crashed instantly. The real-API e2e suite (`pnpm run test:e2e`, the `*.e2e.ts` files) exists precisely to close that gap: it drives the agent against the live DeepSeek API — real model calls, real bash tools, multi-turn, resume, ACP-over-stdio. diff --git a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md index 78bab7c1e0..58a2a87541 100644 --- a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md +++ b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md @@ -1,9 +1,9 @@ -# RFC:在 CI 中对外部 DeepSeek API 运行真实 API e2e 测试 - -[English](2026-06-19-real-api-e2e-ci.md) | 中文 +# RFC: 在 CI 中对外部 DeepSeek API 运行真实 API e2e 测试 Status: implemented +[English](2026-06-19-real-api-e2e-ci.md) | 中文 + ## 问题 按照策略,harness 高度依赖真实 API 测试:[docs/testing.md](../../../testing.md) 论证了无密钥套件只能验证管道连通性而非产品本身,[ACP inject 事后分析](../../../postmortem/0001-acp-default-export-drops-inject.md)是现成的证据——178 个无密钥测试全绿,而真实编辑器会话一启动就崩溃。真实 API e2e 套件(`pnpm run test:e2e`,即 `*.e2e.ts` 文件)正是为弥合这一差距而存在的:它驱动 agent(智能体)对接实时 DeepSeek API——真实模型调用、真实 bash 工具、多轮次对话、恢复、ACP-over-stdio。 diff --git a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.i18n.yaml b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.i18n.yaml index 6e63ef2e55..5f59fbacf1 100644 --- a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-remove-redundant-snapshot-log-goldens.md: badd32d4479ac6d44bb7be3cd262cba57b1b3a38 -2026-06-20-remove-redundant-snapshot-log-goldens.zh.md: b791fbcc971eb1340f0d43ef6a60ebb29e4711f9 +2026-06-20-remove-redundant-snapshot-log-goldens.md: 18d0a4491eb10a3b4dc56d3d63285c219ba6a00a +2026-06-20-remove-redundant-snapshot-log-goldens.zh.md: 5675c69862b6052ed3f3e4710461cc1478b9fa7d diff --git a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.md b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.md index badd32d447..18d0a4491e 100644 --- a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.md +++ b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.md @@ -1,9 +1,9 @@ # RFC: Use `session.jsonl` as the only snapshot session-log artifact -English | [中文](2026-06-20-remove-redundant-snapshot-log-goldens.zh.md) - Status: implemented +English | [中文](2026-06-20-remove-redundant-snapshot-log-goldens.zh.md) + ## Problem Model-driving ACP snapshot scenarios ship both `session.jsonl` and `session.golden.jsonl`. For normal recorded scenarios, `session.jsonl` is the replay fixture harvested from a real run, and the replay test normalizes the newly persisted log and compares it to `session.golden.jsonl`. In the current fixtures, the normalized recorded log and normalized golden are identical for the ordinary recorded scenarios. diff --git a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.zh.md b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.zh.md index b791fbcc97..5675c69862 100644 --- a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.zh.md +++ b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.zh.md @@ -1,4 +1,4 @@ -# RFC:使用 `session.jsonl` 作为唯一的快照会话日志产物 +# RFC: 使用 `session.jsonl` 作为唯一的快照会话日志产物 Status: implemented diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml index f3bddc661c..cfae43ecf0 100644 --- a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-22-fork-child-replay-seed-boundary.md: a0bf064508107a23147df1a6c824c53a3906c43e -2026-06-22-fork-child-replay-seed-boundary.zh.md: 3825cce806c036c7fa21641a2f0b7cc0533d84bf +2026-06-22-fork-child-replay-seed-boundary.md: 28ce76309da2dca7076dd11211229a0631d11db3 +2026-06-22-fork-child-replay-seed-boundary.zh.md: 92b60589b4cfe9668a1542405693cec8d29eceaf diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.md b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.md index a0bf064508..28ce76309d 100644 --- a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.md +++ b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.md @@ -1,9 +1,9 @@ # RFC: Persist the seed boundary so fork-child replay routes correctly -English | [中文](2026-06-22-fork-child-replay-seed-boundary.zh.md) - Status: implemented +English | [中文](2026-06-22-fork-child-replay-seed-boundary.zh.md) + ## Problem The [per-session snapshot replay RFC](2026-06-22-subagent-snapshot-replay.md) made the snapshot tier express a nested-agent shape: a parent plus one recorded log per in-process subagent, each replayed as its own script keyed by calling session. It noted (§ Scope, final bullet) that a fork snapshot was "a trivial future addition, not a gap in the keying." That was wrong about a fork child specifically — not the keying, but the *script derivation*. diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md index 3825cce806..92b60589b4 100644 --- a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md +++ b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md @@ -1,9 +1,9 @@ -# RFC:持久化 seed 边界以确保 fork 子会话回放正确路由 - -[English](2026-06-22-fork-child-replay-seed-boundary.md) | 中文 +# RFC: 持久化 seed 边界以确保 fork 子会话回放正确路由 Status: implemented +[English](2026-06-22-fork-child-replay-seed-boundary.md) | 中文 + ## 问题 [逐会话快照回放 RFC](2026-06-22-subagent-snapshot-replay.md) 让快照层表达了嵌套 agent(智能体)的形状:一个父会话加上每个进程内 subagent 各一份已录制的日志,各自作为独立脚本回放、以调用方会话为键。该 RFC 指出(§ Scope 末尾条目)fork 快照是「一个平凡的后续补充,不是键控方案的缺口」。这对 fork 子会话而言是错的——问题不在键控,而在*脚本推导*。 diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml index d262a105ce..e487e40249 100644 --- a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-22-fork-snapshot-scenarios.md: baca94d6a1071ec38ee20ca841fc3472a870b1a2 -2026-06-22-fork-snapshot-scenarios.zh.md: b6f3f6a6f318a343d5e32573d39f11f59b509ee3 +2026-06-22-fork-snapshot-scenarios.md: a5324cbfa13b79c0ea60b74b689f1b19db99a725 +2026-06-22-fork-snapshot-scenarios.zh.md: 543382db86eb50b5f278a99de74586a13bff9eb7 diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.md b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.md index baca94d6a1..a5324cbfa1 100644 --- a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.md +++ b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.md @@ -1,9 +1,9 @@ # RFC: Record fork and mixed spawn+fork snapshot scenarios -English | [中文](2026-06-22-fork-snapshot-scenarios.zh.md) - Status: implemented +English | [中文](2026-06-22-fork-snapshot-scenarios.zh.md) + ## Problem The [seed-boundary RFC](2026-06-22-fork-child-replay-seed-boundary.md) made fork-child replay route correctly: `dsh-llm-replay` derives a child's script from the events at or after its persisted `seedLength` boundary, so a fork child's inherited parent prefix is not replayed as the child's own model calls. But it shipped with **no recorded fork scenario** — the slice was exercised only by `llm-replay`'s unit tests (a synthetic child fixture) and a persistence round-trip test. The full-transcript snapshot tier, the one net that boots the real `acp-agent` and replays an end-to-end nested transcript, had only spawn children (`subagent-spawn`, `subagent-multi`). A fork-routing regression that left the unit tests green would still have escaped the tier built to catch transcript regressions. diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md index b6f3f6a6f3..543382db86 100644 --- a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md +++ b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md @@ -1,4 +1,4 @@ -# RFC:记录 fork 与混合 spawn+fork 快照场景 +# RFC: 记录 fork 与混合 spawn+fork 快照场景 Status: implemented @@ -8,7 +8,7 @@ Status: implemented [seed-boundary RFC](2026-06-22-fork-child-replay-seed-boundary.md) 使 fork 子会话的回放路由正确运作:`dsh-llm-replay` 从子会话持久化的 `seedLength` 边界处或之后的事件推导出子会话的脚本,因此 fork 子会话继承的父会话前缀不会被当作子会话自身的模型调用来回放。但该 RFC 交付时**没有记录 fork 场景**——该切片仅由 `llm-replay` 的单元测试(一个合成的子会话 fixture(测试前置数据))和一个持久化往返测试覆盖。全 transcript(文本记录)快照层(即启动真实 `acp-agent` 并回放端到端嵌套 transcript 的那张网)只有 spawn 子会话(`subagent-spawn`、`subagent-multi`)。如果一个 fork 路由回归让单元测试保持绿色,它仍然会逃过专为捕获 transcript 回归而建的那一层。 -表达 fork 场景所需的快照基础设施已经就位:两个进程内后端都在 `cordis.yml` / `cordis.snapshot.yml` 中以两个面向模型的工具接入(`subagent` → spawn、`subagent_fork` → fork),harness 会收集每个子会话的日志,回放按 `seedLength` 为键转发各子会话的 fixture。缺少的是一个**已记录的场景**来驱动 fork 子会话走完这条路径。 +表达 fork 场景所需的快照基础设施已经就位:两个进程内后端都在 `cordis.yml` / `cordis.snapshot.yml` 中以两个面向模型的工具接入(`subagent` → spawn、`subagent_fork` → fork),harness 会收集每个子会话的日志,回放按 `seedLength` 为键转发各子会话的 fixture。缺少的是一个*已记录的场景*来驱动 fork 子会话走完这条路径。 ## 决策 @@ -19,12 +19,12 @@ Status: implemented ### 为什么需要一个已完成的第一轮次 -fork 后端用父会话的**已完成轮次的平衡前缀**([`completedTurnPrefix`](../../../../packages/subagent/subagent-fork))来初始化子会话。如果父会话在第一轮次就 fork,则没有已完成的轮次可继承,seed 为空(等价于全新 spawn,`seedLength` 为 0),这**不会**覆盖切片逻辑。因此两个场景都使用双 prompt 输入:第一个 prompt 完成一个轮次(建立一个 codeword,子会话稍后被要求回忆它),第二个 prompt 委派 fork。子会话 transcript 中回忆出的 codeword 只是模型行为的附带产物;真正承载验证的产物是子会话 fixture 中记录的 `seedLength`,回放切片消费的正是它。 +fork 后端用父会话的**已完成轮次的平衡前缀**([`completedTurnPrefix`](../../../../packages/subagent/subagent-fork))来初始化子会话。如果父会话在第一轮次就 fork,则没有已完成的轮次可继承,seed 为空(等价于全新 spawn,`seedLength` 为 0),这不会覆盖切片逻辑。因此两个场景都使用双 prompt 输入:第一个 prompt 完成一个轮次(建立一个 codeword,子会话稍后被要求回忆它),第二个 prompt 委派 fork。子会话 transcript 中回忆出的 codeword 只是模型行为的附带产物;真正承载验证的产物是子会话 fixture 中记录的 `seedLength`,回放切片消费的正是它。 ## 后果 - fork 路由切片现在由全 transcript 层守卫,而不仅仅是单元测试。移除 `slice(seedLength)`(回放整个子会话日志)会让**两个**新场景变红——fork 子会话收到的是父会话记录的 chunk 而非自己的——证明守卫确实生效(场景落地时已验证红→绿)。 -- `subagent-mixed` 是第一个在同一个 transcript 中驱动两种**不同** subagent 后端的快照场景,同时覆盖了跨 spawn 和 fork 子会话的 per-session 回放键控。 +- `subagent-mixed` 是第一个在同一个 transcript 中驱动两种*不同* subagent 后端的快照场景,同时覆盖了跨 spawn 和 fork 子会话的 per-session 回放键控。 - 进程外(ACP)subagent 回放形态不同(每个子会话是独立进程、有自己的回放),仍以 `TODO(acp-subagent-replay)` 跟踪——本文场景仅限进程内。 - 重新录制(`pnpm run test:snapshot:record`)会从真实 API 重新生成全部四个 fork/spawn fixture;两个新场景在无密钥时自动跳过,与所有已录制场景一致。 diff --git a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml index 8bea2c8a5e..c8d42599e1 100644 --- a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-22-subagent-snapshot-replay.md: fbb2e5b93cced118a24f5560f229e2dc341bf3b2 -2026-06-22-subagent-snapshot-replay.zh.md: 6514a0bcb5db3948f6d8f4693b17a74e4a9ad926 +2026-06-22-subagent-snapshot-replay.md: 89fc4e8d4d267fd4df373a7fd82b8c6e742be6ea +2026-06-22-subagent-snapshot-replay.zh.md: 7dc234ab9c6e3bb1facd78e98aad15005d158325 diff --git a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.md b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.md index fbb2e5b93c..89fc4e8d4d 100644 --- a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.md +++ b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.md @@ -1,9 +1,9 @@ # RFC: Per-session snapshot replay for nested agents -English | [中文](2026-06-22-subagent-snapshot-replay.zh.md) - Status: implemented +English | [中文](2026-06-22-subagent-snapshot-replay.zh.md) + ## Problem The snapshot tier (`pnpm run test:snapshot`) boots the real `acp-agent` subprocess, replays a recorded session through [`dsh-llm-replay`](../../../../packages/support/llm-replay), and diffs the normalized stdout transcript + re-persisted session log against committed goldens. It is the only tier that exercises the full editor-facing transcript end to end. diff --git a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md index 6514a0bcb5..7dc234ab9c 100644 --- a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md +++ b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md @@ -1,9 +1,9 @@ -# RFC:嵌套 agent 的逐会话快照回放 - -[English](2026-06-22-subagent-snapshot-replay.md) | 中文 +# RFC: 嵌套 agent 的逐会话快照回放 Status: implemented +[English](2026-06-22-subagent-snapshot-replay.md) | 中文 + ## 问题 快照测试层(`pnpm run test:snapshot`)启动真实的 `acp-agent` 子进程,通过 [`dsh-llm-replay`](../../../../packages/support/llm-replay) 回放录制的会话,并将归一化后的 stdout transcript(文本记录)与重新持久化的会话日志对已提交的金标文件做 diff。这是唯一一个端到端验证完整编辑器侧 transcript 的测试层。 @@ -29,7 +29,7 @@ Status: implemented 活跃会话 id 每次运行都是全新随机值,永远不等于录制时的 id,因此活跃会话无法通过 id 相等绑定到脚本。取而代之的是**首次调用顺序**绑定:第一个发起任何模型调用的活跃会话认领第一份有序脚本(即父会话:`createdAt` 最早,且必然最先流式输出,因为它必须先运行一个轮次才能委派),下一个新活跃会话认领下一份脚本,依此类推。此后每个会话独立推进自己的游标。 -这种方式按**谁在调用**键控,而非按全局调用顺序。因此即使 subagent 将来并发或在后台运行(全局游标会导致交错),它仍然正确。不携带 `sessionId` 的调用(直接在单元测试中调用 `stream()`)被视为一个匿名会话、绑定到主脚本,因此单会话路径与旧行为逐字节一致。活跃会话数多于录制脚本数时会快速失败报错(出现了未录制的 subagent),绝不会静默错误路由。 +这种方式按谁在调用键控,而非按全局调用顺序。因此即使 subagent 将来并发或在后台运行(全局游标会导致交错),它仍然正确。不携带 `sessionId` 的调用(直接在单元测试中调用 `stream()`)被视为一个匿名会话、绑定到主脚本,因此单会话路径与旧行为逐字节一致。活跃会话数多于录制脚本数时会快速失败报错(出现了未录制的 subagent),绝不会静默错误路由。 子 fixture(测试前置数据)按 `createdAt` 排序,在兄弟会话严格顺序执行时与调用顺序一致。id 平局打破仅使退化碰撞具有确定性。并发或后台子会话必须引入显式的首次调用序号,而非依赖时间戳。 @@ -54,5 +54,5 @@ Status: implemented - `TODO(subagent-snapshots)` 延期项已解决:嵌套 agent 的 transcript 现在是快照层的一等形态。 - `GenerateOptions.sessionId` 是一个小而诚实的 core-seam 新增,在回放之外同样有用(遥测、请求路由)。 -- `subagent` 工具绑定到单一提供方,因此 `subagent-multi` 中的两个子 agent 都是 spawn(全新创建)。键控按会话路由而非按后端路由,因此对 fork 同样正确。但脚本**派生**逻辑此前不正确:fork 子会话的日志以种子化的父前缀(父会话的 `assistant/chunk` 事件)开头,如果从完整日志派生脚本,就会把父 agent 的响应当作子 agent 的来回放。这一正确性缺口通过持久化种子边界来弥合——见 [Persist the seed boundary so fork-child replay routes correctly](2026-06-22-fork-child-replay-seed-boundary.md)——录制的 fork 与混合 spawn+fork 场景现在通过一份 transcript 同时验证两种传输方式(见 [Record fork and mixed spawn+fork snapshot scenarios](2026-06-22-fork-snapshot-scenarios.md))。 +- `subagent` 工具绑定到单一提供方,因此 `subagent-multi` 中的两个子 agent 都是 spawn(全新创建)。键控按会话路由而非按后端路由,因此对 fork 同样正确。但脚本*派生*逻辑此前不正确:fork 子会话的日志以种子化的父前缀(父会话的 `assistant/chunk` 事件)开头,如果从完整日志派生脚本,就会把父 agent 的响应当作子 agent 的来回放。这一正确性缺口通过持久化种子边界来弥合——见 [Persist the seed boundary so fork-child replay routes correctly](2026-06-22-fork-child-replay-seed-boundary.md)——录制的 fork 与混合 spawn+fork 场景现在通过一份 transcript 同时验证两种传输方式(见 [Record fork and mixed spawn+fork snapshot scenarios](2026-06-22-fork-snapshot-scenarios.md))。 - 进程外(ACP)subagent 是完全不同的回放形态(每个子 agent 是自己的进程、有自己的回放),作为 `TODO(acp-subagent-replay)` 记录在 PR3 计划中。 diff --git a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml index a0daca4800..8c06af4e98 100644 --- a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-04-hook-snapshot-matrix.md: 8505e82fb681975c7506102a3eb858a29ccc11c8 -2026-07-04-hook-snapshot-matrix.zh.md: 9a9f085400e938bc15c171f652d65f7bcdfa518f +2026-07-04-hook-snapshot-matrix.md: b365992c01e081e5698e81a9ff9682e9b8166ce6 +2026-07-04-hook-snapshot-matrix.zh.md: bcb8e5ba55a14dd0c299dac161146a19f18201eb diff --git a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.md b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.md index 8505e82fb6..b365992c01 100644 --- a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.md +++ b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.md @@ -1,9 +1,9 @@ # RFC: Hook snapshot matrix — end-to-end goldens for both bridges -English | [中文](2026-07-04-hook-snapshot-matrix.zh.md) - Status: implemented +English | [中文](2026-07-04-hook-snapshot-matrix.zh.md) + ## Problem The hook bridges — [`dsh-hooks-claude`](../../../../packages/hooks/hooks-claude) (7 Claude Code hook points) and [`dsh-hooks-codex`](../../../../packages/hooks/hooks-codex) (5 Codex points) — map external hook commands onto the harness interception seams. They carry deep unit and coverage-spec coverage (every decision arm, every payload dialect, driven against a mocked seam) plus one key-gated e2e (`hooks.e2e.ts`, a live `PreToolUse` block). But the full-transcript snapshot tier — the one net that boots the real `acp-agent` subprocess, replays a recorded session keyless, and diffs the normalized ACP stdout + re-persisted log against committed goldens — covered exactly ONE hook: a Claude `UserPromptSubmit` block (`hook-cc-promptsubmit-block`). diff --git a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md index 9a9f085400..bcb8e5ba55 100644 --- a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md +++ b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md @@ -1,4 +1,4 @@ -# RFC:Hook 快照矩阵——覆盖两种 bridge 的端到端 golden 测试 +# RFC: Hook 快照矩阵——覆盖两种 bridge 的端到端 golden 测试 Status: implemented @@ -6,7 +6,7 @@ Status: implemented ## 问题 -hook bridge——[`dsh-hooks-claude`](../../../../packages/hooks/hooks-claude)(7 个 Claude Code hook 点)和 [`dsh-hooks-codex`](../../../../packages/hooks/hooks-codex)(5 个 Codex 点)——将外部 hook 命令映射到 harness 的拦截 seam 上。它们拥有深度的单元测试和 coverage-spec 覆盖率(每个决策分支、每种 payload 方言,均对 mock 的 seam 驱动),外加一个需要密钥的 e2e 测试(`hooks.e2e.ts`,一次真实的 `PreToolUse` 拦截)。但完整 transcript(文本记录)快照层:那张真正启动 `acp-agent` 子进程、无密钥回放录制会话、并将规范化的 ACP stdout 与重新持久化的日志与已提交 golden 做 diff 的网,只覆盖了**一个** hook:Claude 的 `UserPromptSubmit` 拦截(`hook-cc-promptsubmit-block`)。 +hook bridge——[`dsh-hooks-claude`](../../../../packages/hooks/hooks-claude)(7 个 Claude Code hook 点)和 [`dsh-hooks-codex`](../../../../packages/hooks/hooks-codex)(5 个 Codex 点)——将外部 hook 命令映射到 harness 的拦截 seam 上。它们拥有深度的单元测试和 coverage-spec 覆盖率(每个决策分支、每种 payload 方言,均对 mock 的 seam 驱动),外加一个需要密钥的 e2e 测试(`hooks.e2e.ts`,一次真实的 `PreToolUse` 拦截)。但完整 transcript(文本记录)快照层:那张真正启动 `acp-agent` 子进程、无密钥回放录制会话、并将规范化的 ACP stdout 与重新持久化的日志与已提交 golden 做 diff 的网,只覆盖了一个 hook:Claude 的 `UserPromptSubmit` 拦截(`hook-cc-promptsubmit-block`)。 这正是 mock 单元测试在结构上无法替代的层级:它验证的是真实 bridge 将真实 hook 进程的结果翻译到真实 seam 决策,再到真实 agent loop(智能体循环)的反应,渲染结果与编辑器看到的完全一致。一个 bridge 翻译或 loop 结构的回归,即使让所有单元测试保持绿色,也会在除那一个 hook 点之外的所有点上逃逸;而对于 Codex bridge,ACP 示例甚至没有加载它,因此没有任何 Codex hook 能端到端触发。 @@ -29,22 +29,22 @@ hook bridge——[`dsh-hooks-claude`](../../../../packages/hooks/hooks-claude) - **手工编写、无模型轮次**(无密钥、无 sidecar——派生的回放脚本为空;比对的是携带 `hook/*` 事件的 `rejected` 轮次):`hook-cc-promptsubmit-block`、`hook-codex-promptsubmit-block`。 - **对真实 API 录制、录制期间 hook 活跃**(模型对决策的反应是捕获的 transcript 的一部分,此后无密钥回放):`hook-{cc,codex}-promptsubmit-context`(allow + additionalContext 折叠)、`hook-cc-pretool-deny` / `hook-codex-pretool-block`(deny → `isError` 工具结果)、`hook-cc-pretool-ask`(ask → 降级为 deny 并附带 approval-required 原因)、`hook-{cc,codex}-posttool-block`(block 并附带反馈)、`hook-{cc,codex}-posttool-context`(accept + additionalContext)、`hook-{cc,codex}-stop-continue`(阻塞性 Stop hook 通过 steering(中途引导)强制多走一步)。 -每个 hook 命令只输出**固定字面量字符串**(无时间戳/pid/`$RANDOM`/cwd 回显);快照规范化器擦除 `hook/result` 携带的唯一不稳定字段(`durationMs`)。`Stop` 场景通过标记文件(`.stop_fired`)自限,使 force-continue 不会循环——`stop_hook_active` 循环守卫仍是 bridge 的一个 `TODO`,因此无条件的 Stop hook 会在每一步都 force-continue。 +每个 hook 命令只输出固定字面量字符串(无时间戳/pid/`$RANDOM`/cwd 回显);快照规范化器擦除 `hook/result` 携带的唯一不稳定字段(`durationMs`)。`Stop` 场景通过标记文件(`.stop_fired`)自限,使 force-continue 不会循环——`stop_hook_active` 循环守卫仍是 bridge 的一个 `TODO`,因此无条件的 Stop hook 会在每一步都 force-continue。 ### 三个 hook 点被有意排除在快照之外 在构建矩阵过程中发现,记录于此是因为这些遗漏是决策而非疏忽: -- **`SessionStart` 与 `SubagentStart`** 通过一个分离的、尽力而为的 `void runPoint(...).then(agent.inject())` 注入上下文,**没有**轮次绑定。由此产生的 `context/message` 与它所先于的工作(首次模型请求/子 agent 的首轮)存在竞争,落在日志中的位置不确定。录制的 golden 甚至无法在自身回放中复现——10 次回放稳定性检查对两者均 10/10 失败。它们留在 bridge 的单元覆盖率中,单元测试直接驱动 seam 而无时序竞争。(如果注入将来变为轮次绑定且确定性的——`TODO(session-start-gating)` 所指的方向——它们就可以纳入快照。) -- **`SubagentStop`** 是纯观察性的:其 `subagent/end` 处理器不传递轮次(因此无 `hook/*` 日志事件)、不做注入。它对 transcript **不写入任何内容**,因此 golden 与无 hook 运行逐字节一致,永远无法被证明失败——一道永远不会触发的守卫。它留在单元覆盖率中(`bridge.spec.ts` 已断言了纯观察调用)。 +- **`SessionStart` 与 `SubagentStart`** 通过一个分离的、尽力而为的 `void runPoint(...).then(agent.inject())` 注入上下文,没有轮次绑定。由此产生的 `context/message` 与它所先于的工作(首次模型请求/子 agent 的首轮)存在竞争,落在日志中的位置不确定。录制的 golden 甚至无法在自身回放中复现——10 次回放稳定性检查对两者均 10/10 失败。它们留在 bridge 的单元覆盖率中,单元测试直接驱动 seam 而无时序竞争。(如果注入将来变为轮次绑定且确定性的——`TODO(session-start-gating)` 所指的方向——它们就可以纳入快照。) +- **`SubagentStop`** 是纯观察性的:其 `subagent/end` 处理器不传递轮次(因此无 `hook/*` 日志事件)、不做注入。它对 transcript 不写入任何内容,因此 golden 与无 hook 运行逐字节一致,永远无法被证明失败——一道永远不会触发的守卫。它留在单元覆盖率中(`bridge.spec.ts` 已断言了纯观察调用)。 -因此,该矩阵覆盖了所有具有**确定性、可观测** transcript 足迹的 hook 点,涵盖两种方言。 +因此,该矩阵覆盖了所有具有确定性、可观测 transcript 足迹的 hook 点,涵盖两种方言。 ## 后果 - 每个具有可观测 transcript 的 bridge seam 映射现在都在完整 transcript 层级、在真实应用中、对两种方言受到守护——包括此前完全没有端到端覆盖率的 Codex bridge。录制的 golden 捕获了模型对 deny/block/force-continue 轮次的真实反应,这是手工编写的 transcript 只能猜测的。 - block 场景无需密钥(无模型轮次);其余场景从录制的 fixture(测试前置数据)无密钥回放。`pnpm run test:snapshot:record` 从真实 API 重新生成录制的 fixture,无密钥时自动跳过,与所有录制场景一致。 -- prove-red 纪律成立:篡改 hook 配置的输出(例如修改 deny 原因)会使其场景在回放时变红——hook 进程在回放期间**真实运行**(只有模型被回放),因此 golden 守护的是实际的 hook→seam→loop 路径,而非它的 mock。 +- prove-red 纪律成立:篡改 hook 配置的输出(例如修改 deny 原因)会使其场景在回放时变红——hook 进程在回放期间真实运行(只有模型被回放),因此 golden 守护的是实际的 hook→seam→loop 路径,而非它的 mock。 - `acp-agent` 演示现在加载了一个通常会无操作的 Codex bridge(典型项目中没有 `codex-hooks.json`),这正是预期的柔性失败行为,而非代价。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml index 4aa9340c22..733f3a2115 100644 --- a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-04-single-source-acp-replay-config.md: 922bdcced50f8e289449e05b51774f202228b0f8 -2026-07-04-single-source-acp-replay-config.zh.md: b347186f362fa5454f7bd5106c2e261cb8a00b61 +2026-07-04-single-source-acp-replay-config.md: 51cbd54d45408df1548c9cc2522b07b5ffaac110 +2026-07-04-single-source-acp-replay-config.zh.md: 2aec0e0e46007be243c0386fc0fca92065ce3c9e diff --git a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.md b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.md index 922bdcced5..51cbd54d45 100644 --- a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.md +++ b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.md @@ -1,9 +1,9 @@ # RFC: Single-source the acp-agent replay config -English | [中文](2026-07-04-single-source-acp-replay-config.zh.md) - Status: implemented +English | [中文](2026-07-04-single-source-acp-replay-config.zh.md) + ## Problem `examples/acp-agent` shipped two hand-maintained configs: `cordis.yml` (the live tree) and a `cordis.snapshot.yml` that mirrored it entry-for-entry with only the llm backend swapped — stripped of comments, the entire difference was the eight-line `llm-deepseek` stanza versus the two-line `llm-replay` stanza. Every app-shape change had to be made twice, and nothing gated the symmetry: if the copies drifted, the snapshot tier would silently exercise a different app than the one that ships — the ["green units, broken product" class of gap](../../../postmortem/0001-acp-default-export-drops-inject.md) the snapshot tier exists to close, reintroduced one level up, with reviewer vigilance as the only defense. diff --git a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md index b347186f36..2aec0e0e46 100644 --- a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md +++ b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md @@ -1,9 +1,9 @@ -# RFC:将 acp-agent 回放配置改为单一来源 - -[English](2026-07-04-single-source-acp-replay-config.md) | 中文 +# RFC: 将 acp-agent 回放配置改为单一来源 Status: implemented +[English](2026-07-04-single-source-acp-replay-config.md) | 中文 + ## 问题 `examples/acp-agent` 曾维护两份手写配置:`cordis.yml`(正式运行树)和 `cordis.snapshot.yml`(逐条镜像前者,仅替换 LLM(大语言模型)后端)。去掉注释后,全部差异只是八行的 `llm-deepseek` 段落换成两行的 `llm-replay` 段落。每次应用结构变更都要改两遍,且没有门禁保障对称性:一旦两份副本漂移,快照层就会悄悄测试一个与实际交付不同的应用——正是快照层本要消除的["单元测试全绿、产品却坏了"这类缺口](../../../postmortem/0001-acp-default-export-drops-inject.md),在上一层被重新引入,唯一的防线是评审者的警觉。 @@ -23,5 +23,5 @@ overlay 依赖一个 vendor 插件的事实,这是有意为之:include 在 ## 后果 - 向 `cordis.yml` 添加插件即自动进入回放树,无需第二次编辑;漂移这一类问题从结构上消失,而非靠门禁拦截。 -- overlay 依赖条目携带稳定的 `id:`。禁用补丁上的 `name` 断言防止误定位(id 被复用时补丁跳过而非禁用错误的插件)。如果 id 被**重命名**,补丁退化为跳过,其警告需要一个回放应用有意不具备的 logger——可观测结果是一条无效的无密钥 `llm-deepseek` 条目与 `llm-replay` 并存,回放输出仍然正确(`llm-replay` 拥有流的短路权);这属于配置腐烂,留给评审发现,不会产生错误的快照。顶层插入一个 id 与既有条目冲突的新条目时,loader 的 id map 以后者为准;当前配置无冲突,新增补丁行才是引入冲突的场所。 +- overlay 依赖条目携带稳定的 `id:`。禁用补丁上的 `name` 断言防止误定位(id 被复用时补丁跳过而非禁用错误的插件)。如果 id 被重命名,补丁退化为跳过,其警告需要一个回放应用有意不具备的 logger——可观测结果是一条无效的无密钥 `llm-deepseek` 条目与 `llm-replay` 并存,回放输出仍然正确(`llm-replay` 拥有流的短路权);这属于配置腐烂,留给评审发现,不会产生错误的快照。顶层插入一个 id 与既有条目冲突的新条目时,loader 的 id map 以后者为准;当前配置无冲突,新增补丁行才是引入冲突的场所。 - 如果未来回放树需要第二处差异(另一个后端被替换),只需多加一行补丁,而非再 fork 一份文件。 diff --git a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml index 3b2d92e28c..dfb09d507a 100644 --- a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-06-pin-request-header-content-in-one-scenario.md: 5ccaa23a268114c5ba37ec153f4960b47df13bfd -2026-07-06-pin-request-header-content-in-one-scenario.zh.md: 909968430dc3e648e09eeeedd47436c35b90b870 +2026-07-06-pin-request-header-content-in-one-scenario.md: 0166b459fbb8d883f07fb195bdd5e025d70349de +2026-07-06-pin-request-header-content-in-one-scenario.zh.md: 1ca7df68fc743b919c6769ae8fa40ea16eb3d88a diff --git a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md index 5ccaa23a26..0166b459fb 100644 --- a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md +++ b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md @@ -1,9 +1,9 @@ # RFC: Pin request-header content in one snapshot scenario -English | [中文](2026-07-06-pin-request-header-content-in-one-scenario.zh.md) - Status: implemented +English | [中文](2026-07-06-pin-request-header-content-in-one-scenario.zh.md) + ## Problem An ACP snapshot suite needs to prove the exact composed system prompt and tool-schema list sent in each `request/header`, but duplicating that content inside every `session.jsonl` makes a prompt or schema edit rewrite dozens of giant one-line JSON records. Keeping one raw header avoids the duplication but still makes prompt review poor: prose is JSON-escaped onto one line and mixed with thousands of characters of tool schemas. diff --git a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md index 909968430d..1ca7df68fc 100644 --- a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md +++ b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md @@ -1,4 +1,4 @@ -# RFC:在单个快照场景中固定请求头内容 +# RFC: 在单个快照场景中固定请求头内容 Status: implemented diff --git a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml index c582f34c23..e8c8a129b8 100644 --- a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-08-shared-acp-snapshot-package.md: 81714191a704af1a9ed029fb8004deac88e39427 -2026-07-08-shared-acp-snapshot-package.zh.md: f80c8e49e80e9bf287c84c0ff4fb00377fad5175 +2026-07-08-shared-acp-snapshot-package.md: c378222804251761a1b04f59c35799a97a1525f1 +2026-07-08-shared-acp-snapshot-package.zh.md: cda7a578d4643800736ff159a6427d3a0e3e0fae diff --git a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.md b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.md index 81714191a7..c378222804 100644 --- a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.md +++ b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.md @@ -1,9 +1,9 @@ # RFC: Extract the ACP snapshot suite into a support package -English | [中文](2026-07-08-shared-acp-snapshot-package.zh.md) - Status: implemented +English | [中文](2026-07-08-shared-acp-snapshot-package.zh.md) + ## Problem The ACP snapshot tier ([snapshot RFC](2026-06-19-acp-snapshot-tests.md)) was built from three modules living inside one example's test directory: `snapshot-harness.ts` (boot the real bin subprocess, drive it over ACP JSON-RPC, harvest the persisted logs), `snapshot-normalize.ts` (the pure golden normalizers), and the ~150-line scenario body plus fixture guards in `acp.snapshot.ts` (record/replay modes, the stdout-golden and log compares, the pinned-header uniformity guard, the orphan/required-file/single-pin meta-tests). diff --git a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md index f80c8e49e8..cda7a578d4 100644 --- a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md +++ b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md @@ -1,9 +1,9 @@ -# RFC:将 ACP 快照套件提取为支持包 - -[English](2026-07-08-shared-acp-snapshot-package.md) | 中文 +# RFC: 将 ACP 快照套件提取为支持包 Status: implemented +[English](2026-07-08-shared-acp-snapshot-package.md) | 中文 + ## 问题 ACP 快照层([快照 RFC](2026-06-19-acp-snapshot-tests.md))由位于某个示例测试目录中的三个模块构成:`snapshot-harness.ts`(启动真实 bin 子进程,通过 ACP JSON-RPC 驱动它,收集持久化日志)、`snapshot-normalize.ts`(纯粹的 golden 规范化器),以及 `acp.snapshot.ts` 中约 150 行的场景主体加 fixture(测试前置数据)守卫(record/replay 模式、stdout-golden 与日志比对、pinned-header 一致性守卫、orphan/required-file/single-pin 元测试)。 diff --git a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml index 59f21c938e..b355adb77d 100644 --- a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml +++ b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-16-typed-event-schemas.md: 8d14c3b2d90d8dcf295e122e95267c2c0d7b2a17 -2026-06-16-typed-event-schemas.zh.md: 34f46a87058b409ecdab38d851654db49d87e201 +2026-06-16-typed-event-schemas.md: 93e470218e810c9c9370dd1c7cae5420c93fa7bf +2026-06-16-typed-event-schemas.zh.md: bca4265527507750abe5b8c114f14508cee91cb9 diff --git a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.md b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.md index 8d14c3b2d9..93e470218e 100644 --- a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.md +++ b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.md @@ -1,9 +1,9 @@ # RFC: Runtime schemas for the event vocabulary (Zod vs the merge-extensible-map pattern) -English | [中文](2026-06-16-typed-event-schemas.zh.md) - Status: proposed +English | [中文](2026-06-16-typed-event-schemas.zh.md) + ## Problem The harness models its core vocabulary — content blocks, message sources, finish reasons, turn triggers, turn-end reasons, and session events — as **merge-extensible maps**: a TypeScript `interface` (e.g. `SessionEventMap`, `ContentBlockMap`) that plugins augment via declaration merging, with the public union derived as `Map[keyof Map]`. This is the repo's universal extension pattern, documented in [docs/architecture.md](../../../architecture.md) ("The same merge-extensible-map pattern is used for `MessageSource`, `FinishReason`, `TurnTrigger`, and `TurnEndReason`") and relied on by the `defineTool` `InferArgs` DSL and the `assertNever` exhaustiveness convention. diff --git a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.zh.md b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.zh.md index 34f46a8705..bca4265527 100644 --- a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.zh.md +++ b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.zh.md @@ -1,16 +1,16 @@ -# RFC:事件词汇的运行时 schema(Zod 与 merge-extensible-map 模式之辩) - -[English](2026-06-16-typed-event-schemas.md) | 中文 +# RFC: 事件词汇的运行时 schema(Zod 与 merge-extensible-map 模式之辩) Status: proposed +[English](2026-06-16-typed-event-schemas.md) | 中文 + ## 问题 harness 将其核心词汇——内容块、消息来源、结束原因、轮次触发器、轮次结束原因与会话事件——建模为 **merge-extensible map**:一个 TypeScript `interface`(如 `SessionEventMap`、`ContentBlockMap`),插件通过声明合并对其扩展,公开联合类型则以 `Map[keyof Map]` 派生。这是本仓库的通用扩展模式,记录在 [docs/architecture.md](../../../architecture.md) 中("The same merge-extensible-map pattern is used for `MessageSource`, `FinishReason`, `TurnTrigger`, and `TurnEndReason`"),`defineTool` 的 `InferArgs` DSL 和 `assertNever` 穷举约定都依赖于它。 该模式**仅存在于编译期**。类型在运行时消失:没有 schema 对象可供校验传入值、解析不可信输入或在运行时枚举变体。[会话持久化契约](../../implemented/architecture/2026-06-14-session-persistence.md)暴露了两个后果: -1. **持久化将 `event.data` 视为不透明 JSON。** JSONL/SQLite 后端对每个事件逐字 `JSON.stringify`/`JSON.parse`;唯一的运行时守卫是 `isJsonValue`(往返可序列化性检查:拒绝 BigInt、函数、循环引用、非有限数等),而**非**结构校验。一个损坏但仍为合法 JSON 的事件数据(字段类型错误、字段缺失)会静默往返,只有在后续消费方的 `switch` 中才可能被捕获。 +1. **持久化将 `event.data` 视为不透明 JSON。** JSONL/SQLite 后端对每个事件逐字 `JSON.stringify`/`JSON.parse`;唯一的运行时守卫是 `isJsonValue`(往返可序列化性检查:拒绝 BigInt、函数、循环引用、非有限数等),而非结构校验。一个损坏但仍为合法 JSON 的事件数据(字段类型错误、字段缺失)会静默往返,只有在后续消费方的 `switch` 中才可能被捕获。 2. **插件新增变体没有运行时契约。** 一个通过声明合并添加新 `SessionEventMap` 键的插件,在自身代码中获得了编译期类型,但没有任何机制校验它产出的值是否符合它所声明的形状——无论是在生产者处、持久化边界处还是重新加载时。 由此引出问题:事件词汇是否应迁移到 **Zod** 或其他运行时 schema 库,使持久化和插件边界拥有运行时 schema 而非被擦除的类型。 diff --git a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml index 290a729be7..b98f0fa227 100644 --- a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml +++ b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-generic-long-running-tool-runtime.md: ea773a651b5aeec87179aac2ed419f176486977f -2026-06-20-generic-long-running-tool-runtime.zh.md: 25c1b282b19bb7da08b552485e348c23b11dcecf +2026-06-20-generic-long-running-tool-runtime.md: 9b83a4443d6d654cda75c72fba3369a16be078e2 +2026-06-20-generic-long-running-tool-runtime.zh.md: c1684be4fd5c1c3c9d913e063f4ba66bb6064459 diff --git a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md index ea773a651b..9b83a4443d 100644 --- a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md +++ b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md @@ -1,9 +1,9 @@ # RFC: Extract a generic long-running tool runtime -English | [中文](2026-06-20-generic-long-running-tool-runtime.zh.md) - Status: proposed +English | [中文](2026-06-20-generic-long-running-tool-runtime.zh.md) + ## Problem The bash capability seam supports both foreground commands and long-running background tasks. Background support is large: the abstract executor exposes `start`, `get`, `ownerOf`, `list`, `readOutput`, `kill`, and `onTaskDone`; the local executor tracks tasks, incremental reads, owner tokens, process cleanup, and completion listeners; the model sees three tools (`bash`, `bash_output`, `bash_kill`); the tool plugin injects completion notices back into the owning agent's session. The local executor fences task access behind owner tokens because predictable global task ids are a cross-session read/kill hazard. diff --git a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md index 25c1b282b1..c1684be4fd 100644 --- a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md +++ b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md @@ -1,4 +1,4 @@ -# RFC:提取通用的长时间运行工具运行时 +# RFC: 提取通用的长时间运行工具运行时 Status: proposed diff --git a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml index ccab930c8f..3412d91229 100644 --- a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml +++ b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-30-pre-tool-input-rewrite.md: add84bfc76434eb25870f09e71860279663d291e -2026-06-30-pre-tool-input-rewrite.zh.md: 13d66208be07992fd414f2984c493557ad1e87a3 +2026-06-30-pre-tool-input-rewrite.md: 85ece78f3bf188b3b702b1af539256747c1cfab2 +2026-06-30-pre-tool-input-rewrite.zh.md: 6a5c2b52627d21476b96448dc120155eab7f2223 diff --git a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.md b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.md index add84bfc76..85ece78f3b 100644 --- a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.md +++ b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.md @@ -1,9 +1,9 @@ # RFC: Pre-tool input rewrite — a consistent design -English | [中文](2026-06-30-pre-tool-input-rewrite.zh.md) - Status: proposed +English | [中文](2026-06-30-pre-tool-input-rewrite.zh.md) + ## Problem The [interception-seams RFC](../../implemented/feature/2026-06-30-interception-seams.md) defines `tools/pre-execute` as an allow/deny/ask gate over an execution whose identity is already protected and whose arguments are deeply frozen. Claude Code's `PreToolUse` hook also offers `updatedInput`, so a faithful bridge needs an explicit rewrite mechanism. A rewrite cannot be a mutation escape hatch on the existing execution object: it must keep the durable history, audit record, presentation, and executed value consistent. diff --git a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md index 13d66208be..6a5c2b5262 100644 --- a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md +++ b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md @@ -1,4 +1,4 @@ -# RFC:工具执行前输入重写——一致性设计 +# RFC: 工具执行前输入重写——一致性设计 Status: proposed @@ -10,7 +10,7 @@ Status: proposed ## 问题本质:执行前参数的三个读取方 -在 agent loop(智能体循环)中,工具调用的参数在工具执行**之前**就已提交到日志并被实时消费方读取: +在 agent loop(智能体循环)中,工具调用的参数在工具执行之前就已提交到日志并被实时消费方读取: 1. **`assistant/message`** 在工具分发之前追加——它是 `deriveMessages()` 回放时的模型历史来源,因此携带模型自身输出的工具调用参数。 2. **`tool/call`** 是持久化的审计记录,在 `ctx.tools.execute()` 之前追加。 @@ -22,7 +22,7 @@ Status: proposed 重写是一个「身份标识创建前的一致性事务」。当钩子提供 `updatedInput` 时,有效值必须在注册表构造其不可变的 `ToolExecution` 之前确定,并且必须原子地反映到全部三个读取方: -- `tool/call` 审计事件记录**重写后**的参数(原始参数保留在一个伴随字段中,作为审计线索——钩子修改了调用,原始参数与生效参数都是值得保留的事实)。 +- `tool/call` 审计事件记录重写后的参数(原始参数保留在一个伴随字段中,作为审计线索——钩子修改了调用,原始参数与生效参数都是值得保留的事实)。 - 派生历史中的 `assistant/message` 必须与实际执行一致。待评估的选项:就地重写 assistant 消息中的工具调用块(改变模型「看到自己说了什么」),或记录一条单独的修正让下一次请求携带。Claude Code 的模型是让模型看到重写已生效。 - 展示层(`presentCall`/`presentResult`)读取重写后的参数,使 UI 显示实际运行的内容。 diff --git a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml index ab362ca036..e3ec2ad677 100644 --- a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml +++ b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-07-claude-code-and-codex-subagent-backends.md: 1ebf01dd8df0980f6c464be8b27033bdfab942f3 -2026-07-07-claude-code-and-codex-subagent-backends.zh.md: dd26a49962ee46a8ce0965557ff3dbd5805fdcfe +2026-07-07-claude-code-and-codex-subagent-backends.md: 5585ea30a5ba1b4200f096069a28ccf1c3cef727 +2026-07-07-claude-code-and-codex-subagent-backends.zh.md: 2a6dd2cdea34cb777df5455f0bc12dc7073ff2a2 diff --git a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.md b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.md index 1ebf01dd8d..5585ea30a5 100644 --- a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.md +++ b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.md @@ -1,9 +1,9 @@ # RFC: Claude Code and Codex subagent backends (out-of-process delegation to external coding agents) -English | [中文](2026-07-07-claude-code-and-codex-subagent-backends.zh.md) - Status: proposed +English | [中文](2026-07-07-claude-code-and-codex-subagent-backends.zh.md) + ## Problem Add isolated subagent providers for Claude Code and Codex. The existing [named-provider seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) and [ACP backend](../../implemented/feature/2026-06-22-acp-subagent-backend.md) establish the process-boundary shape. A harness turn should be able to delegate a self-contained task to either product and receive its final answer without exposing parent secrets or inheriting host configuration from `~/.claude` or `~/.codex`. diff --git a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md index dd26a49962..2a6dd2cdea 100644 --- a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md +++ b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md @@ -1,9 +1,9 @@ -# RFC:Claude Code 与 Codex subagent 后端(向外部编码 agent 的进程外委派) - -[English](2026-07-07-claude-code-and-codex-subagent-backends.md) | 中文 +# RFC: Claude Code 与 Codex subagent 后端(向外部编码 agent 的进程外委派) Status: proposed +[English](2026-07-07-claude-code-and-codex-subagent-backends.md) | 中文 + ## 问题 为 Claude Code 和 Codex 添加隔离的 subagent 提供方。既有的[命名提供方 seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 和 [ACP 后端](../../implemented/feature/2026-06-22-acp-subagent-backend.md)已确立了进程边界的形状。harness 的一个轮次应能将一个自包含任务委派给上述任一产品,并接收其最终答案,同时不暴露父进程的密钥,也不继承来自 `~/.claude` 或 `~/.codex` 的宿主配置。 @@ -12,7 +12,7 @@ Status: proposed 两个兄弟提供方包(ACP 后端的结构变体),加一次提取: -- `@deepseek-ai/dsh-subagent-claude-code`:通过 `@anthropic-ai/claude-agent-sdk` 的 `query()` 驱动一个 Claude Code 子进程(SDK 在父进程中运行,并将其内置的 `claude` CLI 作为子进程 spawn)。提供方名称为 `claude-code`:子进程是 Claude Code 这个**产品**,而非 Anthropic 模型适配器——"claude" 保留给未来的 `dsh-llm` 适配器。 +- `@deepseek-ai/dsh-subagent-claude-code`:通过 `@anthropic-ai/claude-agent-sdk` 的 `query()` 驱动一个 Claude Code 子进程(SDK 在父进程中运行,并将其内置的 `claude` CLI 作为子进程 spawn)。提供方名称为 `claude-code`:子进程是 Claude Code 这个*产品*,而非 Anthropic 模型适配器——"claude" 保留给未来的 `dsh-llm` 适配器。 - `@deepseek-ai/dsh-subagent-codex`:spawn `codex app-server`,通过其 JSON-RPC-over-stdio 协议驱动一个 thread/turn,使用包内一个手写的换行 JSON 客户端(约 200–300 行)。 - `@deepseek-ai/dsh-subagent-process`:纯库(沿用 `subagent-inprocess` 的先例),提取 `dsh-subagent-acp` 已有且两个新后端都需要的内容:凭证环境清洗(`SENSITIVE_ENV_PATTERN`/`buildChildEnv`)、EOF → SIGTERM → SIGKILL 的 dispose 阶梯,以及新的隔离配置目录辅助函数(`mkdtemp` 创建、尽力删除)。ACP 后端迁移到该库上;`bash-local` 的兄弟副本保持不动以限制变更范围。 @@ -22,13 +22,13 @@ Status: proposed 两个集成面在本提案之前均已针对固定版本进行了验证——阅读类型与打包源码、运行无需密钥的 spike——而非仅依赖厂商文档。固定版本是验证基线,不是运行时契约:后端不执行运行时版本探测(无 `codex --version` 门禁、无 SDK 版本嗅探)。兼容性在开发时强制执行——每次依赖升级都会针对真实加载路径重跑无密钥套件——在运行时则通过大声失败来保障:协议层面的意外通过 `onError` 结算为 `error`,绝不静默异常。 -**`@anthropic-ai/claude-agent-sdk` 0.3.202。** `options.env` 会**替换**子进程环境(不与 `process.env` 合并),恰好满足清洗需求。`settingSources` 默认加载所有文件系统设置——隔离要求显式传入 `[]`。结果子类型为 `success` | `error_during_execution` | `error_max_turns` | `error_max_budget_usd` | `error_max_structured_output_retries`。中止时 SDK 自行升级 CLI 子进程:立即关闭 stdin,约 2 秒后若子进程未退出则发送 SIGTERM(已观察到;无残留进程)——无需自定义 kill 回退。`outputFormat: {type: 'json_schema'}` 和 `agents` 选项已存在,为 seam 的 `outputSchema` 能力和命名 subagent 类型提供了未来着陆点;两者均不在本 RFC 范围内。 +**`@anthropic-ai/claude-agent-sdk` 0.3.202。** `options.env` 会替换子进程环境(不与 `process.env` 合并),恰好满足清洗需求。`settingSources` 默认加载所有文件系统设置——隔离要求显式传入 `[]`。结果子类型为 `success` | `error_during_execution` | `error_max_turns` | `error_max_budget_usd` | `error_max_structured_output_retries`。中止时 SDK 自行升级 CLI 子进程:立即关闭 stdin,约 2 秒后若子进程未退出则发送 SIGTERM(已观察到;无残留进程)——无需自定义 kill 回退。`outputFormat: {type: 'json_schema'}` 和 `agents` 选项已存在,为 seam 的 `outputSchema` 能力和命名 subagent 类型提供了未来着陆点;两者均不在本 RFC 范围内。 **codex CLI 0.142.5,`codex app-server`(v2 词汇)。** LF 分隔的 JSON,JSON-RPC 2.0 形状但省略 `"jsonrpc"` 头。 - 生命周期:`initialize{clientInfo}` + `initialized` → `thread/start`(接受 `cwd`、`model`、`sandbox`、`approvalPolicy`、`ephemeral`;未认证即可成功)→ `turn/start{threadId, input:[{type:'text',text}]}` 立即返回一个 `inProgress` 的 turn;终止信号是携带 `Turn{status: completed|interrupted|failed|inProgress, error}` 的 `turn/completed` 通知。 - 审批是服务端发起的请求——`item/commandExecution/requestApproval`、`item/fileChange/requestApproval`、`item/permissions/requestApproval`、`item/tool/requestUserInput`、`mcpServer/elicitation/request`——以 `accept`/`decline` 系列决策应答。 -- 认证:`account/login/start{type:'apiKey', apiKey}` 是一等 RPC,`account/read` 报告 `requiresOpenaiAuth`——且未认证的 `turn/start` 不会快速失败(它会挂在重试中),因此后端**必须**预检认证状态,并在失败时大声结算为 `error`,而非等待 turn。 +- 认证:`account/login/start{type:'apiKey', apiKey}` 是一等 RPC,`account/read` 报告 `requiresOpenaiAuth`——且未认证的 `turn/start` 不会快速失败(它会挂在重试中),因此后端必须预检认证状态,并在失败时大声结算为 `error`,而非等待 turn。 - 隔离:`CODEX_HOME` 重定向被尊重(`initialize` 响应会回显它,测试可据此断言隔离),`ephemeral: true` 的 thread 不留任何会话文件。 ## 隔离与凭证 @@ -43,7 +43,7 @@ Status: proposed Claude Code:`success` → `completed`;`error_max_turns`、`error_during_execution`、`error_max_budget_usd`、`error_max_structured_output_retries` → `error`(与 ACP 对 `max_turn_requests` 的处理对齐:未完成的任务不是成功);生成器中止 → `aborted`;未知值 → `error`。Codex:`Turn.status` 为 `completed` → `completed`;`interrupted` → `aborted`;`failed` 且 `codexErrorInfo: 'contextWindowExceeded'` → `max-tokens`,其他 `failed` → `error`;传输/spawn/认证预检失败 → `error`(若已请求取消则为 `aborted`)。两者中,`cancel()` 采用 ACP 形状:标志位 + abort/interrupt + 一个 cancel-settled 竞争分支,使不合作的子进程无法阻塞结果。 -活性姿态,明确声明:teardown 时序是配置项,turn 时长不是。两个后端将 dispose 阶梯的宽限期作为带默认值的已验证配置字段(ACP 后端的 `disposeEofGraceMs`/`disposeGraceMs` 形状,由提取库承载),但**刻意不设** turn 时长或启动超时——与 ACP 一致:turn 期间的活性由调用方通过 `cancel()`/abort signal 掌控,subagent turn 合理地可达数分钟,而 Codex 认证预检消除了唯一已验证的必然挂起场景;需要墙钟上限的部署从父侧取消即可。 +活性姿态,明确声明:teardown 时序是配置项,turn 时长不是。两个后端将 dispose 阶梯的宽限期作为带默认值的已验证配置字段(ACP 后端的 `disposeEofGraceMs`/`disposeGraceMs` 形状,由提取库承载),但刻意不设 turn 时长或启动超时——与 ACP 一致:turn 期间的活性由调用方通过 `cancel()`/abort signal 掌控,subagent turn 合理地可达数分钟,而 Codex 认证预检消除了唯一已验证的必然挂起场景;需要墙钟上限的部署从父侧取消即可。 ## 测试 @@ -61,7 +61,7 @@ dispose 阶梯和环境清洗要求拥有子进程(spawn 参数、env、信号 ### 为什么不用模型可见的 `subagent_type` 参数(单一 Task 风格工具)? -Claude Code 自身的 Task 工具将 subagent 类型放在模型可见的 schema 中,选择一个 prompt + 工具集人格。这里的选择是在**执行引擎**之间做出的,而只有部署者知道哪些引擎配置了凭证——因此选择留在部署配置层,保持 `dsh-tool-subagent` 文档中的「一个提供方对应一个工具」契约。人格风格的类型选择器应是针对工具的另一个 RFC,而非针对后端。 +Claude Code 自身的 Task 工具将 subagent 类型放在模型可见的 schema 中,选择一个 prompt + 工具集人格。这里的选择是在执行引擎之间做出的,而只有部署者知道哪些引擎配置了凭证——因此选择留在部署配置层,保持 `dsh-tool-subagent` 文档中的「一个提供方对应一个工具」契约。人格风格的类型选择器应是针对工具的另一个 RFC,而非针对后端。 ### 为什么不用登录态凭证和用户自身的配置? diff --git a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml index a86bcca889..b7300fc7f3 100644 --- a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml +++ b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-08-interactive-side-sessions.md: 250a906d9ec339399a0e0e29e70b2b8dc189fa72 -2026-07-08-interactive-side-sessions.zh.md: d86a2b69232bc8ccad78555911b44cf727780e0c +2026-07-08-interactive-side-sessions.md: ac29f80b31492ce79512cc4d08e33480e0ac6258 +2026-07-08-interactive-side-sessions.zh.md: 5d0ef101dc23febefec881b12fcbb5ba4dcf8be9 diff --git a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.md b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.md index 250a906d9e..ac29f80b31 100644 --- a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.md +++ b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.md @@ -1,9 +1,9 @@ # RFC: Interactive side sessions and merge-back -English | [中文](2026-07-08-interactive-side-sessions.zh.md) - Status: proposed +English | [中文](2026-07-08-interactive-side-sessions.zh.md) + ## Problem A user may want to explore a question from a live session without changing its main context. Existing primitives do not expose that product shape: [session-store fork](../../implemented/feature/2026-06-30-session-store-fork-api.md) creates an unattached session, while [fork subagents](../../implemented/feature/2026-06-21-subagent-capability-seam.md) are model-driven tasks whose transcript collapses into one tool result. Neither gives the user a separate conversation, and neither records a conclusion back into the parent with provenance. diff --git a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.zh.md b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.zh.md index d86a2b6923..5d0ef101dc 100644 --- a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.zh.md +++ b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.zh.md @@ -1,9 +1,9 @@ -# RFC:交互式侧会话与合并回写 - -[English](2026-07-08-interactive-side-sessions.md) | 中文 +# RFC: 交互式侧会话与合并回写 Status: proposed +[English](2026-07-08-interactive-side-sessions.md) | 中文 + ## 问题 用户可能希望在不改变当前会话主上下文的前提下,探索一个来自活跃会话的问题。现有原语无法提供这种产品形态:[session-store fork](../../implemented/feature/2026-06-30-session-store-fork-api.md) 创建的是一个无关联的会话,而 [fork subagent](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 是模型驱动的任务,其 transcript(文本记录)会折叠为一条工具结果。两者都不能给用户一个独立的对话,也都不能将结论带着出处信息记录回父会话。 diff --git a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml index ab712ad131..5a09704cff 100644 --- a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml +++ b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-10-sqlite-session-query-provider.md: 8b67baf420433feca9d5cd09d58852bb9b1545a9 -2026-07-10-sqlite-session-query-provider.zh.md: ad6b44363ab54b66b597941adb13938f27971bd5 +2026-07-10-sqlite-session-query-provider.md: d1901ab0e37e8f92af322facac0cb48988d1ffe7 +2026-07-10-sqlite-session-query-provider.zh.md: 7a86d7294183eec57c3495a182f1403f84c27363 diff --git a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.md b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.md index 8b67baf420..d1901ab0e3 100644 --- a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.md +++ b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.md @@ -1,9 +1,9 @@ # RFC: SQLite FTS5 session search -English | [中文](2026-07-10-sqlite-session-query-provider.zh.md) - Status: proposed +English | [中文](2026-07-10-sqlite-session-query-provider.zh.md) + ## Problem The exact-read `ctx.sessionQuery` service deliberately has no derived index. Large persisted histories need full-text search without scanning every event on every query, while current live sessions need an overlay newer than the last durability checkpoint. Search also needs concrete ranking, snippets, filters, pagination, cancellation, and rebuild behavior. diff --git a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md index ad6b44363a..7a86d72941 100644 --- a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md +++ b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md @@ -1,9 +1,9 @@ -# RFC:SQLite FTS5 会话搜索 - -[English](2026-07-10-sqlite-session-query-provider.md) | 中文 +# RFC: SQLite FTS5 会话搜索 Status: proposed +[English](2026-07-10-sqlite-session-query-provider.md) | 中文 + ## 问题 精确读取的 `ctx.sessionQuery` 服务有意不维护派生索引。大规模持久化的历史记录需要全文搜索,而不是每次查询都扫描全部事件;当前的活跃会话则需要一个比上一次持久性检查点更新的覆盖层。搜索还需要具体的排序、摘要片段、过滤、分页、取消以及重建行为。 diff --git a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml index a90fafdf8b..802373dd50 100644 --- a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml +++ b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-13-stream-workflow-progress-through-tool-calls.md: 525f2793052a80d82de29d2d370cfd747d002af6 -2026-07-13-stream-workflow-progress-through-tool-calls.zh.md: 8dcb4aea2de50cdd278c702c9f6c85ab66e6be34 +2026-07-13-stream-workflow-progress-through-tool-calls.md: c4fe68974bf774306038e3bd2ba3e29e06de3492 +2026-07-13-stream-workflow-progress-through-tool-calls.zh.md: b6a3ccbc89bebaae92641a10aea9a9a05b38a293 diff --git a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.md b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.md index 525f279305..c4fe68974b 100644 --- a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.md +++ b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.md @@ -1,9 +1,9 @@ # RFC: Stream workflow progress through tool calls -English | [中文](2026-07-13-stream-workflow-progress-through-tool-calls.zh.md) - Status: proposed +English | [中文](2026-07-13-stream-workflow-progress-through-tool-calls.zh.md) + ## Problem The workflow engine intentionally emits balanced `workflow/*` observation events for run, phase, narration, and child-agent progress, but no production consumer presents them. Editors therefore show one pending workflow tool card until the final result even while the engine already reports which phase is active, what the script logged, and which children started or settled. The [dynamic-workflows decision](../../implemented/feature/2026-07-05-dynamic-workflows.md) explicitly reserves ACP progress UI for this event stream. diff --git a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md index 8dcb4aea2d..b6a3ccbc89 100644 --- a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md +++ b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md @@ -1,9 +1,9 @@ -# RFC:通过工具调用流式传输工作流进度 - -[English](2026-07-13-stream-workflow-progress-through-tool-calls.md) | 中文 +# RFC: 通过工具调用流式传输工作流进度 Status: proposed +[English](2026-07-13-stream-workflow-progress-through-tool-calls.md) | 中文 + ## 问题 工作流引擎有意为 run、phase、narration 和子 agent(智能体)进度发出成对的 `workflow/*` observation 事件,但目前没有生产消费方呈现这些事件。因此,编辑器在最终结果返回之前只显示一张 pending 状态的工作流工具卡片,尽管引擎已经报告了当前活跃的 phase、脚本日志内容以及哪些子 agent 已启动或已结束。[dynamic-workflows 决策](../../implemented/feature/2026-07-05-dynamic-workflows.md)明确将 ACP(Agent Client Protocol)进度 UI 保留给这一事件流。 diff --git a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml index fc5effd89a..f7f98a72bb 100644 --- a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml +++ b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-api-extractor-reports.md: 0f3f736ba662fd6366eb8d7f26887fb319b2b563 -2026-06-11-api-extractor-reports.zh.md: cf0eb3f9edbcfb2ae862f075af0628e716693a86 +2026-06-11-api-extractor-reports.md: 26562267d188ab2427075c6fccf0ee4b24d63d99 +2026-06-11-api-extractor-reports.zh.md: 33e80abc6e9689cf90f3c851039144a53418137e diff --git a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.md b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.md index 0f3f736ba6..26562267d1 100644 --- a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.md +++ b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.md @@ -1,9 +1,9 @@ # RFC: API extractor reports -English | [中文](2026-06-11-api-extractor-reports.zh.md) - Status: proposed +English | [中文](2026-06-11-api-extractor-reports.zh.md) + > Split out from the original "Doc-sync and API reports" RFC (2026-06-11). Parts 1-2 (doc-block typechecking, event-taxonomy verification) shipped — see [doc-sync enforcement](../../implemented/process/2026-06-11-doc-sync-enforcement.md). This is the deferred part 3, kept as a standalone proposal. ## Problem diff --git a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.zh.md b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.zh.md index cf0eb3f9ed..33e80abc6e 100644 --- a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.zh.md +++ b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.zh.md @@ -1,9 +1,9 @@ -# RFC:API extractor 报告 - -[English](2026-06-11-api-extractor-reports.md) | 中文 +# RFC: API extractor 报告 Status: proposed +[English](2026-06-11-api-extractor-reports.md) | 中文 + > 从最初的「Doc-sync 与 API 报告」RFC(2026-06-11)中拆出。第 1–2 部分(文档块类型检查、事件分类体系校验)已交付,见 [doc-sync 强制](../../implemented/process/2026-06-11-doc-sync-enforcement.md)。本文是被推迟的第 3 部分,作为独立提案保留。 ## 问题 diff --git a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.i18n.yaml b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.i18n.yaml index 094c2c349b..b358826e19 100644 --- a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.i18n.yaml +++ b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-architectural-conformance.md: 40858d049af2df1928e27280238d0b198a5202f7 -2026-06-11-architectural-conformance.zh.md: b68355dc1c04a4f807efdb95f813159cb7f9f178 +2026-06-11-architectural-conformance.md: aad11b9e4bcbd31465cb0c4a507654971e24e843 +2026-06-11-architectural-conformance.zh.md: 59684bd01a133755a3d7efd90832f6f268037920 diff --git a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.md b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.md index 40858d049a..aad11b9e4b 100644 --- a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.md +++ b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.md @@ -1,9 +1,9 @@ # RFC: Architectural conformance — dependency rules and the adapter kit -English | [中文](2026-06-11-architectural-conformance.zh.md) - Status: proposed +English | [中文](2026-06-11-architectural-conformance.zh.md) + ## Problem Two architectural guarantees currently live only in prose: (1) nothing depends on the concrete loop package ([the microkernel promise](../../implemented/architecture/2026-06-11-microkernel-event-taxonomy.md)), and (2) every LlmAdapter speaks the chunk protocol correctly. Both should be mechanical ([the quality-gates principle](../../implemented/process/2026-06-11-quality-gates.md)). diff --git a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.zh.md b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.zh.md index b68355dc1c..59684bd01a 100644 --- a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.zh.md +++ b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.zh.md @@ -1,9 +1,9 @@ -# RFC:架构一致性——依赖规则与适配器套件 - -[English](2026-06-11-architectural-conformance.md) | 中文 +# RFC: 架构一致性——依赖规则与适配器套件 Status: proposed +[English](2026-06-11-architectural-conformance.md) | 中文 + ## 问题 目前有两项架构保证仅存在于行文中:(1)没有任何东西依赖具体的 loop 包([微内核承诺](../../implemented/architecture/2026-06-11-microkernel-event-taxonomy.md));(2)每个 LlmAdapter 都正确地遵循 chunk 协议。二者都应当是机械化的([质量门禁原则](../../implemented/process/2026-06-11-quality-gates.md))。 diff --git a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml index 62e4b4aa6f..7e89d07146 100644 --- a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml +++ b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-supply-chain-and-vendor-drift.md: 306e185e9175e3e7af24455cf95167f54b3d1c17 -2026-06-11-supply-chain-and-vendor-drift.zh.md: a840e766c49182d7a9ca648acbbab1a2762688f5 +2026-06-11-supply-chain-and-vendor-drift.md: 97f5a3f999936faf81a67fe69c91f773400cb447 +2026-06-11-supply-chain-and-vendor-drift.zh.md: 0a8441c104ca4779a79b36361ea5d84f5cd09aca diff --git a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.md b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.md index 306e185e91..97f5a3f999 100644 --- a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.md +++ b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.md @@ -1,9 +1,9 @@ # RFC: Supply chain checks and vendor drift verification -English | [中文](2026-06-11-supply-chain-and-vendor-drift.zh.md) - Status: proposed +English | [中文](2026-06-11-supply-chain-and-vendor-drift.zh.md) + ## Problem The vendor manifest ([the vendoring decision](../../implemented/process/2026-06-11-vendor-cordis-as-source.md)) is enforced at commit time in the *forward* direction (vendored change ⇒ manifest update) but nothing verifies the manifest's *claims*: that vendor/ actually equals upstream-at-SHA plus exactly the logged modifications. And the handful of true npm dependencies have no advisory monitoring or update cadence. diff --git a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md index a840e766c4..0a8441c104 100644 --- a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md +++ b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md @@ -1,12 +1,12 @@ -# RFC:供应链检查与 vendor 漂移验证 - -[English](2026-06-11-supply-chain-and-vendor-drift.md) | 中文 +# RFC: 供应链检查与 vendor 漂移验证 Status: proposed +[English](2026-06-11-supply-chain-and-vendor-drift.md) | 中文 + ## 问题 -vendor manifest(元数据清单)(见[引入 vendor 的决策](../../implemented/process/2026-06-11-vendor-cordis-as-source.md))在提交时仅在**正向**强制执行(vendor 变更 ⇒ manifest 更新),但没有任何机制验证 manifest 的**声明**:即 vendor/ 确实等于上游指定 SHA 的内容加上所记录的修改。此外,少量真正的 npm 依赖也没有安全公告监控或更新节奏。 +vendor manifest(元数据清单)(见[引入 vendor 的决策](../../implemented/process/2026-06-11-vendor-cordis-as-source.md))在提交时仅在*正向*强制执行(vendor 变更 ⇒ manifest 更新),但没有任何机制验证 manifest 的*声明*:即 vendor/ 确实等于上游指定 SHA 的内容加上所记录的修改。此外,少量真正的 npm 依赖也没有安全公告监控或更新节奏。 ## 提案 diff --git a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml index ddaafef6da..678dcb4abe 100644 --- a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml +++ b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-discover-package-inventory.md: 22b3e9acbe4dad8ef829d0dd30415c516031d66b -2026-06-20-discover-package-inventory.zh.md: 4eeaed9ed6b390608095281775883f8e7a52e954 +2026-06-20-discover-package-inventory.md: 6729b8ea4386b1595139a2827a95cf3b072e8c94 +2026-06-20-discover-package-inventory.zh.md: 71a6fdf97255932dcff11b574ef7c67ef5a39313 diff --git a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.md b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.md index 22b3e9acbe..6729b8ea43 100644 --- a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.md +++ b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.md @@ -1,9 +1,9 @@ # RFC: Discover package inventories instead of maintaining static lists -English | [中文](2026-06-20-discover-package-inventory.zh.md) - Status: proposed +English | [中文](2026-06-20-discover-package-inventory.zh.md) + ## Problem Package and gate inventories are repeated across TypeScript project references, package docs, CI prose, Knip overrides, and snapshot scenario metadata. Most restate package layout, manifest data, aggregate command contents, or fixture files. Each new package or scenario therefore creates avoidable synchronization points. diff --git a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.zh.md b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.zh.md index 4eeaed9ed6..71a6fdf972 100644 --- a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.zh.md +++ b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.zh.md @@ -1,4 +1,4 @@ -# RFC:通过发现机制获取包清单,而非维护静态列表 +# RFC: 通过发现机制获取包清单,而非维护静态列表 Status: proposed @@ -14,7 +14,7 @@ Status: proposed ## 提案 -让剩余的包/门禁清单可被发现。一个唯一的权威来源——`packages/<group>/<pkg>` 层级结构加上包 manifest(元数据清单)——应当驱动 `tsconfig.build.json` 的 `references`、模块图以及任何全量包列表,并配合一个生成加校验步骤(沿用现有的 `gen-module-graph` / `gen-cordis-catalog` 模式:生成器写出产物,`hygiene`/doc-sync(文档同步门禁)中的 `--check` 模式在提交副本陈旧时报错)。模块图生成已经在读取包 manifest。`doc-sync` 应当成为定义并打印其子门禁的唯一命令,文档链接到该命令而非重述第二份列表。 +让剩余的包/门禁清单可被发现。一个唯一的权威来源——`packages/<group>/<pkg>` 层级结构加上包 manifest(元数据清单)——应当驱动 `tsconfig.build.json` 的 `references`、模块图以及任何全量包列表,并配合一个生成加校验步骤(沿用现有的 `gen-module-graph` / `gen-cordis-catalog` 模式:生成器写出产物,`hygiene`/`doc-sync`(文档同步门禁)中的 `--check` 模式在提交副本陈旧时报错)。模块图生成已经在读取包 manifest。`doc-sync` 应当成为定义并打印其子门禁的唯一命令,文档链接到该命令而非重述第二份列表。 层级结构不需要编码关于包的所有事实,但应当编码宽泛的维护策略:core/product 包、集成包、能力 seam 包与 support/test/example 包不应在脚本能区分它们之前先要求一份手工维护的例外列表。 diff --git a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml index dde7a0ad32..1c1c0eb757 100644 --- a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml +++ b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-unify-agent-and-session-id.md: 3a6daa411673003eb1c3017e7a717ae4bf98b735 -2026-06-20-unify-agent-and-session-id.zh.md: 6b1b996879125c6ab85aed7ba419aff15d077b42 +2026-06-20-unify-agent-and-session-id.md: 9cec898a2df9418b3533c776779c88fc50bc7dcb +2026-06-20-unify-agent-and-session-id.zh.md: 39e78db0b886d1e0b13afe2337697a184af478ed diff --git a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.md b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.md index 3a6daa4116..9cec898a2d 100644 --- a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.md +++ b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.md @@ -1,9 +1,9 @@ # RFC: Unify the agent id and the session id -English | [中文](2026-06-20-unify-agent-and-session-id.zh.md) - Status: proposed +English | [中文](2026-06-20-unify-agent-and-session-id.zh.md) + ## Problem The agent factory carries two ids for each live agent/session pair: `agentId`, the `AgentRegistry` routing handle, and `sessionId`, the event-sourced and persisted-log identity. `CreateAgentOptions` takes both; `ResumeAgentOptions` takes `agentId` plus `resumeSessionId`; in-process subagents mint two independent UUIDs despite recording lineage separately. diff --git a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.zh.md b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.zh.md index 6b1b996879..39e78db0b8 100644 --- a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.zh.md +++ b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.zh.md @@ -1,9 +1,9 @@ -# RFC:统一 agent id 与 session id - -[English](2026-06-20-unify-agent-and-session-id.md) | 中文 +# RFC: 统一 agent id 与 session id Status: proposed +[English](2026-06-20-unify-agent-and-session-id.md) | 中文 + ## 问题 agent 工厂为每个活跃的 agent/session 对维护两个 id:`agentId`(`AgentRegistry` 的路由句柄)和 `sessionId`(事件溯源与持久化日志的标识)。`CreateAgentOptions` 接收两者;`ResumeAgentOptions` 接收 `agentId` 加 `resumeSessionId`;进程内 subagent 各自铸造两个独立的 UUID,尽管血缘关系另行记录。 diff --git a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml index 4420b2dd27..d828a634b5 100644 --- a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml +++ b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-04-prune-dead-core-spine-surface.md: c46fe464e8627dcfc39a1d3fbb38a9cbd84269cf -2026-07-04-prune-dead-core-spine-surface.zh.md: 67e89a580b086a08aed702d9e0b87bdb6e32c944 +2026-07-04-prune-dead-core-spine-surface.md: 59bbfa181a08b998c52ef63afbc63fd5226294a6 +2026-07-04-prune-dead-core-spine-surface.zh.md: 953cb3bc7b30affd505564ac427632732dd9374e diff --git a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.md b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.md index c46fe464e8..59bbfa181a 100644 --- a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.md +++ b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.md @@ -1,9 +1,9 @@ # RFC: Prune dead public and result surface -English | [中文](2026-07-04-prune-dead-core-spine-surface.zh.md) - Status: proposed +English | [中文](2026-07-04-prune-dead-core-spine-surface.zh.md) + ## Problem Several package-root exports, result fields, and convenience methods have no production consumer. They survive because tests import internals through public entry points or because a type anticipated a caller that never arrived. Each item is small in isolation, but together they enlarge the SDK contract, generated catalogs, documentation, and regression matrix without enabling a shipped path. diff --git a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md index 67e89a580b..953cb3bc7b 100644 --- a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md +++ b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md @@ -1,4 +1,4 @@ -# RFC:裁剪无用的公开与结果接口 +# RFC: 裁剪无用的公开与结果接口 Status: proposed diff --git a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml index 2e91f9e9c2..ff2ae238ba 100644 --- a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml +++ b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-12-simplify-session-log-representation.md: 52720231d6e4cbe0cbb412332cd016ba63f83569 -2026-07-12-simplify-session-log-representation.zh.md: 1286a7d3c571fac66310a613c548920c3f25812d +2026-07-12-simplify-session-log-representation.md: dd8e7f319098bcdca9a844f5665583a3aa25ae80 +2026-07-12-simplify-session-log-representation.zh.md: c759b87bbb13903744a8f6bbb139ab71e1c0f39b diff --git a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.md b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.md index 52720231d6..dd8e7f3190 100644 --- a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.md +++ b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.md @@ -1,9 +1,9 @@ # RFC: Simplify session-log representation -English | [中文](2026-07-12-simplify-session-log-representation.zh.md) - Status: proposed +English | [中文](2026-07-12-simplify-session-log-representation.zh.md) + ## Problem The session log maintains two representations that cost more machinery than their consumers require: a pseudo-linked surface and custom request-header deltas. diff --git a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.zh.md b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.zh.md index 1286a7d3c5..c759b87bbb 100644 --- a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.zh.md +++ b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.zh.md @@ -1,9 +1,9 @@ -# RFC:简化会话日志表示 - -[English](2026-07-12-simplify-session-log-representation.md) | 中文 +# RFC: 简化会话日志表示 Status: proposed +[English](2026-07-12-simplify-session-log-representation.md) | 中文 + ## 问题 会话日志维护着两种表示,其机制复杂度超出了消费方的实际需求:一个伪链表 surface 和自定义的请求头增量。 diff --git a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml index 13dc3e72b9..4c6aa9f685 100644 --- a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml +++ b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-deterministic-and-stress-testing.md: e4ed7043d1880b55dd7d77b3e09a81dd58739a70 -2026-06-11-deterministic-and-stress-testing.zh.md: 4e4ee9d28025a43349b702e399096535539a91d2 +2026-06-11-deterministic-and-stress-testing.md: c629567fd16158a0bd081e7e7850fb3e6d5f1631 +2026-06-11-deterministic-and-stress-testing.zh.md: aaa170725f9d3d2457d6f418dce7bc53feda2ab7 diff --git a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.md b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.md index e4ed7043d1..c629567fd1 100644 --- a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.md +++ b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.md @@ -1,9 +1,9 @@ # RFC: Deterministic tests, the replay invariant fixture, and race stress -English | [中文](2026-06-11-deterministic-and-stress-testing.zh.md) - Status: proposed +English | [中文](2026-06-11-deterministic-and-stress-testing.zh.md) + ## Problem Several loop tests synchronize with `setTimeout(30)` sleeps — flakiness debt that wastes agent cycles on retries and can mask ordering bugs. Separately, our core architectural promise (any session log replays to identical derived history) is asserted in two tests but is cheap to assert *everywhere*. And the inbox wakeup race was verified by hand exactly once; nothing re-verifies it continuously. diff --git a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md index 4e4ee9d280..aaa170725f 100644 --- a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md +++ b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md @@ -1,12 +1,12 @@ -# RFC:确定性测试、回放不变式 fixture 与竞态压力测试 - -[English](2026-06-11-deterministic-and-stress-testing.md) | 中文 +# RFC: 确定性测试、回放不变式 fixture 与竞态压力测试 Status: proposed +[English](2026-06-11-deterministic-and-stress-testing.md) | 中文 + ## 问题 -若干 agent loop(智能体循环)测试通过 `setTimeout(30)` 睡眠来同步——这是一笔不稳定性债务,浪费 agent 的重试周期,还可能掩盖时序 bug。另外,我们的核心架构承诺(任何会话日志回放后都能得到相同的派生历史)目前只在两个测试中断言,但在**所有**测试中断言的成本极低。此外,inbox 唤醒竞态只被手动验证过一次,没有任何机制持续复验。 +若干 agent loop(智能体循环)测试通过 `setTimeout(30)` 睡眠来同步——这是一笔不稳定性债务,浪费 agent 的重试周期,还可能掩盖时序 bug。另外,我们的核心架构承诺(任何会话日志回放后都能得到相同的派生历史)目前只在两个测试中断言,但在*所有*测试中断言的成本极低。此外,inbox 唤醒竞态只被手动验证过一次,没有任何机制持续复验。 ## 提案 diff --git a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.i18n.yaml b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.i18n.yaml index 3bf5967b45..ce9a12799f 100644 --- a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.i18n.yaml +++ b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-mutation-testing.md: 344263d1c91a5e6c83320f367bf76ed6f7ef5a49 -2026-06-11-mutation-testing.zh.md: 28bb7253c12827dbcddd141481f26f60b3a72b7a +2026-06-11-mutation-testing.md: 20b24de385b944c27f4bdc0fc70f335d827f50a0 +2026-06-11-mutation-testing.zh.md: 780d3417cce48ee19ac8e3dc3b74d78b8e2a4c0f diff --git a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.md b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.md index 344263d1c9..20b24de385 100644 --- a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.md +++ b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.md @@ -1,9 +1,9 @@ # RFC: Mutation testing as the coverage counterweight -English | [中文](2026-06-11-mutation-testing.zh.md) - Status: proposed +English | [中文](2026-06-11-mutation-testing.zh.md) + ## Problem The per-file 100% coverage gate ([the quality-gates decision](../../implemented/process/2026-06-11-quality-gates.md)) proves every line *executes* under test — not that any assertion would notice if the line were wrong. Under agent-written tests, coverage pressure can produce execution-without-assertion. Mutation testing measures what coverage cannot: whether the suite *kills* deliberately injected bugs. diff --git a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.zh.md b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.zh.md index 28bb7253c1..780d3417cc 100644 --- a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.zh.md +++ b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.zh.md @@ -1,9 +1,9 @@ -# RFC:变异测试作为覆盖率的制衡手段 - -[English](2026-06-11-mutation-testing.md) | 中文 +# RFC: 变异测试作为覆盖率的制衡手段 Status: proposed +[English](2026-06-11-mutation-testing.md) | 中文 + ## 问题 逐文件 100% 覆盖率门禁([质量门禁决策](../../implemented/process/2026-06-11-quality-gates.md))证明每一行代码在测试中都被*执行*了,但不能证明如果该行出错,任何断言会注意到。在 agent(智能体)编写测试的场景下,覆盖率压力可能产出「执行但不断言」的测试。变异测试衡量的正是覆盖率无法衡量的:测试套件是否能*杀死*被刻意注入的缺陷。 diff --git a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml index f7c21ad005..31b046d91a 100644 --- a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml +++ b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-11-immutable-public-surfaces.md: 68472d9817f0de22777314927f05f90949903723 -2026-06-11-immutable-public-surfaces.zh.md: 7dc42ef9ff07682c1bbac1ca61caba49596cb7bc +2026-06-11-immutable-public-surfaces.md: c807b036bb57bd5e64290fd59bf422c4732e9080 +2026-06-11-immutable-public-surfaces.zh.md: 9ff40436915e194848ba163ed80fefe84a1b3da4 diff --git a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.md b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.md index 68472d9817..c807b036bb 100644 --- a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.md +++ b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.md @@ -1,9 +1,9 @@ # RFC: Deep-readonly public surfaces -English | [中文](2026-06-11-immutable-public-surfaces.zh.md) - Status: rejected — the pervasive `DeepReadonly<T>` type flip is replaced by source-owned runtime immutability in `Session` plus relational development assertions. See [source-owned session immutability and dev-mode invariants](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md). +English | [中文](2026-06-11-immutable-public-surfaces.zh.md) + ## Problem The rejected proposal targeted an ownership hole that a `readonly SessionEvent[]` type alone cannot close: its elements remain mutable at runtime, so a cast or plain JavaScript can rewrite nested history. The implemented design closes that hole in `Session` by materializing and deep-freezing every accepted event and returning frozen array snapshots. In-flight prompt waterfalls remain intentionally transformable, so immutability is an ownership boundary rather than a blanket type rule. diff --git a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md index 7dc42ef9ff..9ff4043691 100644 --- a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md +++ b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md @@ -1,9 +1,9 @@ -# RFC:深度只读的公开接口 +# RFC: 深度只读的公开接口 + +Status: rejected — the pervasive `DeepReadonly<T>` type flip is replaced by source-owned runtime immutability in `Session` plus relational development assertions. See [source-owned session immutability and dev-mode invariants](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md). [English](2026-06-11-immutable-public-surfaces.md) | 中文 -Status: rejected — 全面使用 `DeepReadonly<T>` 类型翻转的方案已被替换为 `Session` 中由源拥有的运行时不可变性加关系型开发断言。见[源拥有的会话不可变性与开发模式不变式](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md)。 - ## 问题 被否决的提案针对的是一个所有权漏洞:仅靠 `readonly SessionEvent[]` 类型无法封堵该漏洞,因为其元素在运行时仍然可变,类型强制转换或纯 JavaScript 代码可以改写嵌套的历史记录。已实现的设计在 `Session` 中封堵了这一漏洞:对每个被接受的事件进行物化并深度冻结,返回冻结的数组快照。进行中的 prompt waterfall(瀑布式事件)有意保持可变换,因此不可变性是一条所有权边界,而非一条全局类型规则。 @@ -14,7 +14,7 @@ Status: rejected — 全面使用 `DeepReadonly<T>` 类型翻转的方案已被 在类型层面为「突变即损坏」的场景引入不可变性: -- `SessionEvent` 数据在从会话**输出**时(`events`、`session/event` 监听器)变为 `DeepReadonly`;`append()` 仍接受普通可变输入。一个 `DeepReadonly<T>` 工具类型放在 dsh-llm 中,与 brand/never 辅助类型相邻。 +- `SessionEvent` 数据在从会话输出时(`events`、`session/event` 监听器)变为 `DeepReadonly`;`append()` 仍接受普通可变输入。一个 `DeepReadonly<T>` 工具类型放在 dsh-llm 中,与 brand/never 辅助类型相邻。 - `deriveMessages()` 返回深度只读的消息;agent loop(智能体循环)在将可变请求交给 `agent/request` waterfall 之前先克隆(该处的突变是被允许的——克隆使边界显式且代价低廉,每个步骤仅一次)。 - `PromptAssembly` 在其 waterfall 流经期间保持可变(被允许),但注册表内部的 section 列表在每次组装时被克隆(已有此行为)。 diff --git a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml index 11ed0efa0b..e4d9370aa8 100644 --- a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml +++ b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-providerless-example-base.md: be5122ec6665dcea15619f3cb4b3ed3a2fa03972 -2026-06-20-providerless-example-base.zh.md: f01451f719f0fe1bbb50806aea40086e7fe08350 +2026-06-20-providerless-example-base.md: ca9d391172067aca980b5b0fbc17141320c6839e +2026-06-20-providerless-example-base.zh.md: fb64e4a0b5295e0d56e7cd598c230f56219ba77e diff --git a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.md b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.md index be5122ec66..ca9d391172 100644 --- a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.md +++ b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.md @@ -1,9 +1,9 @@ # RFC: Make the shared example base providerless -English | [中文](2026-06-20-providerless-example-base.zh.md) - Status: rejected — superseded by [Extract example apps into packages](../../implemented/architecture/2026-06-20-extract-example-app-packages.md), which moves the spine into a `dsh-agent-spine-demo` bundle and deletes the `base*.yml` files, so there is no shared base YAML left to rename. +English | [中文](2026-06-20-providerless-example-base.zh.md) + ## Problem The examples had two shared base files: `examples/base-core.yml` was providerless, while `examples/base.yml` included that core plus the real `llm-deepseek` adapter. Snapshot replay needs the providerless core with `llm-replay`, because loading the real adapter without a key throws. The normal demos need the real adapter. The result was a naming inversion: the file named `base.yml` was not the reusable base for all examples, while the true base was `base-core.yml`. diff --git a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.zh.md b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.zh.md index f01451f719..fb64e4a0b5 100644 --- a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.zh.md +++ b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.zh.md @@ -1,9 +1,9 @@ -# RFC:使共享示例基础配置与提供方无关 - -[English](2026-06-20-providerless-example-base.md) | 中文 +# RFC: 使共享示例基础配置与提供方无关 Status: rejected — superseded by [Extract example apps into packages](../../implemented/architecture/2026-06-20-extract-example-app-packages.md), which moves the spine into a `dsh-agent-spine-demo` bundle and deletes the `base*.yml` files, so there is no shared base YAML left to rename. +[English](2026-06-20-providerless-example-base.md) | 中文 + ## 问题 示例曾有两个共享基础文件:`examples/base-core.yml` 与提供方无关,而 `examples/base.yml` 在该核心基础上加入了真实的 `llm-deepseek` 适配器。快照回放需要与提供方无关的核心配合 `llm-replay` 使用,因为在没有密钥的情况下加载真实适配器会抛出异常。常规演示则需要真实适配器。结果是命名与实际含义倒挂:名为 `base.yml` 的文件并非所有示例可复用的基础,而真正的基础反倒是 `base-core.yml`。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml index ec03777980..c203585372 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-assembled-assistant-messages-only.md: 7605f286cf5914a127f5f8e2b77490648b42cc30 -2026-06-20-assembled-assistant-messages-only.zh.md: 05f15ffadba4607bc64fdf2f7eefdbcc41cf03a3 +2026-06-20-assembled-assistant-messages-only.md: 48f45ba08f77e2efd79bd999e262afad313bbdfe +2026-06-20-assembled-assistant-messages-only.zh.md: 44d94b3bc3d9c9f0f6c3bb8a2554664c4f5f5c59 diff --git a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.md b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.md index 7605f286cf..48f45ba08f 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.md +++ b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.md @@ -1,9 +1,9 @@ # RFC: Persist assembled assistant messages, not stream chunks -English | [中文](2026-06-20-assembled-assistant-messages-only.zh.md) - Status: rejected — high-fidelity chunk replay, partial failed streams, and snapshot replay currently depend on persisted `assistant/chunk` events. Dropping chunks is only viable with a no-information-loss replay/artifact replacement. +English | [中文](2026-06-20-assembled-assistant-messages-only.zh.md) + ## Problem The canonical session log currently persists every `assistant/chunk` exactly as streamed by the model. The [session persistence RFC](../../implemented/architecture/2026-06-14-session-persistence.md) chose this for token-level replay fidelity and contiguous `seq`, but the cost has grown: JSONL fixtures are dominated by tiny delta records, snapshot scenarios replay the model by grouping chunk events, ACP load reconstructs prior assistant output from chunks, and any future log reader must distinguish durable message history from token-level trace. diff --git a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md index 05f15ffadb..44d94b3bc3 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md @@ -1,9 +1,9 @@ -# RFC:仅持久化组装后的 assistant 消息,不存储流式分片 - -[English](2026-06-20-assembled-assistant-messages-only.md) | 中文 +# RFC: 仅持久化组装后的 assistant 消息,不存储流式分片 Status: rejected — high-fidelity chunk replay, partial failed streams, and snapshot replay currently depend on persisted `assistant/chunk` events. Dropping chunks is only viable with a no-information-loss replay/artifact replacement. +[English](2026-06-20-assembled-assistant-messages-only.md) | 中文 + ## 问题 当前的规范会话日志会持久化模型流式输出的每一个 `assistant/chunk`。[会话持久化 RFC](../../implemented/architecture/2026-06-14-session-persistence.md) 选择这一方案是为了 token 级别的回放保真度和连续的 `seq`,但其代价日益增长:JSONL fixture(测试前置数据)被大量微小的 delta 记录占据,快照场景通过分组 chunk 事件来回放模型,ACP(Agent Client Protocol)加载时从 chunk 重建先前的 assistant 输出,而任何未来的日志读取方都必须区分持久的消息历史与 token 级别的追踪。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml index 35f0ecedd9..764ea5f4e9 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-drop-acp-session-load.md: 39f24d313db6083db45ff6fbc4a84f504e7714cb -2026-06-20-drop-acp-session-load.zh.md: b7339f492d5f6b7e2daab5820dada0fa2b5fe823 +2026-06-20-drop-acp-session-load.md: 93a2791d10b589cfdee5ecc48922722fe27c1c8a +2026-06-20-drop-acp-session-load.zh.md: 94de0a5aa0436dbee8e78fc2dd6de72c98216768 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.md b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.md index 39f24d313d..93a2791d10 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.md @@ -1,9 +1,9 @@ # RFC: Drop ACP session/load until resume has a product shape -English | [中文](2026-06-20-drop-acp-session-load.zh.md) - Status: rejected — Zed is the current target ACP client, advertises and exercises load-capable sessions, and keeps pending-load state for concurrent `session/load`. The bridge should keep `session/load` and make the resume contract solid. +English | [中文](2026-06-20-drop-acp-session-load.zh.md) + ## Problem ACP advertises `loadSession: true` and implements `session/load` by injecting persistence into the bridge, validating cwd against stored metadata, reconstructing an agent from the persisted log, and replaying prior transcript updates to the client. That path has its own race handling, loading-id guard, replay presenter logic, and tests. It also depends on the canonical log retaining enough UI data to reconstruct old chunks and tool presentations. diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md index b7339f492d..94de0a5aa0 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md @@ -1,9 +1,9 @@ -# RFC:移除 ACP session/load,直到 resume 具备产品形态 +# RFC: 移除 ACP session/load,直到 resume 具备产品形态 + +Status: rejected — Zed is the current target ACP client, advertises and exercises load-capable sessions, and keeps pending-load state for concurrent `session/load`. The bridge should keep `session/load` and make the resume contract solid. [English](2026-06-20-drop-acp-session-load.md) | 中文 -Status: rejected — Zed 是当前目标 ACP 客户端,它声明并使用支持 load 的会话,且为并发 `session/load` 维护 pending-load 状态。bridge 应保留 `session/load` 并使 resume 契约更加稳固。 - ## 问题 ACP(Agent Client Protocol)声明 `loadSession: true` 并实现 `session/load`:向 bridge 注入持久化能力、校验 cwd 与存储元数据的一致性、从持久化日志重建 agent(智能体),并向客户端回放先前的 transcript(文本记录)更新。该路径有自己的竞态处理、loading-id 守卫、回放展示逻辑和测试。它还依赖规范日志保留足够的 UI 数据,以重建旧的分片和工具展示。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml index 16827c901b..81bb11c433 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-drop-acp-terminal-meta.md: 4ae3b31824ece850da0ddbc004e97b21e3cb9aad -2026-06-20-drop-acp-terminal-meta.zh.md: f5b3e0a4e1f37445a0b0dcbf7426806a1de89763 +2026-06-20-drop-acp-terminal-meta.md: e52187d9786ed44ef4b60aedf5396c19a2e8e872 +2026-06-20-drop-acp-terminal-meta.zh.md: a5f4d7bc1f9d3d050c23990e89610d3eaed5bf70 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.md b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.md index 4ae3b31824..e52187d978 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.md @@ -1,9 +1,9 @@ # RFC: Drop ACP terminal `_meta` rendering -English | [中文](2026-06-20-drop-acp-terminal-meta.zh.md) - Status: rejected — Zed is the current target client, and the terminal `_meta` convention is intentional Zed UX with a plain ACP fallback for other clients. +English | [中文](2026-06-20-drop-acp-terminal-meta.zh.md) + ## Problem The ACP bridge implements a Zed-specific terminal-card convention through `_meta.terminal_info`, `_meta.terminal_output`, and `_meta.terminal_exit`. The implemented [rich ACP bash rendering RFC](../../implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md) deliberately avoided ACP's client-side `terminal/create` because bash execution belongs in the harness, but still adopted the reference agents' display-only `_meta` convention. That gives a nicer Zed card at the cost of bridge state, capability negotiation, terminal ids, special update mapping, text fallback tests, and exit-pill parsing in `dsh-tool-bash`. diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md index f5b3e0a4e1..a5f4d7bc1f 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md @@ -1,9 +1,9 @@ -# RFC:移除 ACP 终端 `_meta` 渲染 +# RFC: 移除 ACP 终端 `_meta` 渲染 + +Status: rejected — Zed is the current target client, and the terminal `_meta` convention is intentional Zed UX with a plain ACP fallback for other clients. [English](2026-06-20-drop-acp-terminal-meta.md) | 中文 -Status: rejected — Zed 是当前目标客户端,终端 `_meta` 约定是有意为之的 Zed UX 设计,同时为其他客户端提供纯 ACP(Agent Client Protocol)回退路径。 - ## 问题 ACP 桥接层通过 `_meta.terminal_info`、`_meta.terminal_output` 和 `_meta.terminal_exit` 实现了一套 Zed 特有的终端卡片约定。已实现的[富 ACP bash 渲染 RFC](../../implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md) 刻意回避了 ACP 客户端侧的 `terminal/create`(因为 bash 执行属于 harness 职责),但仍采用了参考 agent(智能体)的纯展示 `_meta` 约定。这在 Zed 中带来了更好的卡片效果,代价是桥接状态、能力协商、终端 id、特殊的 update 映射、文本回退测试,以及 `dsh-tool-bash` 中的 exit-pill 解析。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml index de324b8de2..304c4a62ac 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-drop-bash-output-spill-files.md: bbc26c645cefb1659012ca0debda78fc6850d276 -2026-06-20-drop-bash-output-spill-files.zh.md: 43b6029a68542d03027b61424a2a3024ace200d5 +2026-06-20-drop-bash-output-spill-files.md: 939f99072eace71405ae96e270d5438e75713c1c +2026-06-20-drop-bash-output-spill-files.zh.md: 4a868b1971dc3abcb4a9d0442ffc6e74f5246d00 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.md b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.md index bbc26c645c..939f99072e 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.md @@ -1,9 +1,9 @@ # RFC: Drop bash full-output spill files -English | [中文](2026-06-20-drop-bash-output-spill-files.zh.md) - Status: rejected — full-output recovery is a real bash behavior. A future artifact/blob service may generalize it, but dropping spill files before that replacement would lose useful command output. +English | [中文](2026-06-20-drop-bash-output-spill-files.zh.md) + ## Problem `dsh-bash-local` keeps bounded in-memory output and spills large stdout/stderr streams into private temp files. That requires a private directory, random owner-only file creation, close-failure handling, byte-offset incremental reads, lossy read reporting, path rendering in model-facing text, and cleanup discipline. The tool then tells the model to read a local spill path when output was truncated. diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md index 43b6029a68..4a868b1971 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md @@ -1,9 +1,9 @@ -# RFC:移除 bash 完整输出溢出文件 - -[English](2026-06-20-drop-bash-output-spill-files.md) | 中文 +# RFC: 移除 bash 完整输出溢出文件 Status: rejected — full-output recovery is a real bash behavior. A future artifact/blob service may generalize it, but dropping spill files before that replacement would lose useful command output. +[English](2026-06-20-drop-bash-output-spill-files.md) | 中文 + ## 问题 `dsh-bash-local` 在内存中保留有界的输出,并将大体量的 stdout/stderr 流溢出到私有临时文件。这要求一个私有目录、仅所有者可写的随机文件创建、关闭失败处理、基于字节偏移的增量读取、有损读取报告、在面向模型的文本中渲染路径,以及清理纪律。当输出被截断时,该工具会告知模型去读取一个本地溢出路径。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml index 7396bcf5aa..131544ab6d 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-drop-durable-step-boundaries.md: fba8ad4211db69d3a04d253fd9544caca0f538c6 -2026-06-20-drop-durable-step-boundaries.zh.md: e389c5506b03a472c74853f3b73c21681f96287f +2026-06-20-drop-durable-step-boundaries.md: 16fdf17c3bc8907745df17e8a105d7978eafb274 +2026-06-20-drop-durable-step-boundaries.zh.md: 5613a84d5f1b5cf87109a2e04a4cb350ffd650a8 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.md b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.md index fba8ad4211..16fdf17c3b 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.md @@ -1,9 +1,9 @@ # RFC: Drop durable step boundary events -English | [中文](2026-06-20-drop-durable-step-boundaries.zh.md) - Status: rejected — `step/end` is the durable indication that a model step finished, and keeping the symmetric `step/start` / `step/end` pair makes crash repair, invariants, and transcript inspection clearer than inferring completion from adjacent step-scoped events. +English | [中文](2026-06-20-drop-durable-step-boundaries.zh.md) + ## Problem The session log stores `step/start` and `step/end` events even though every step-scoped event already carries `{ turn, step }`: assistant chunks, assistant messages, tool calls, tool results, usage, and errors. `deriveMessages()` ignores step boundaries, ACP ignores them for UI, and the main consumers are invariants, tests, snapshot goldens, and crash repair. diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md index e389c5506b..5613a84d5f 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md @@ -1,4 +1,4 @@ -# RFC:移除持久化的步骤边界事件 +# RFC: 移除持久化的步骤边界事件 Status: rejected — `step/end` is the durable indication that a model step finished, and keeping the symmetric `step/start` / `step/end` pair makes crash repair, invariants, and transcript inspection clearer than inferring completion from adjacent step-scoped events. diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml index f2aab138ee..3302d9bef1 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-drop-unused-session-lineage.md: 4200532726a27e257e09f927240846f20a0b30ad -2026-06-20-drop-unused-session-lineage.zh.md: 1524987111f12a9c6e2014723bb1cb4c87bcf940 +2026-06-20-drop-unused-session-lineage.md: 5f76baf33fa50fc1aff9a0ab43262f063aa8e51b +2026-06-20-drop-unused-session-lineage.zh.md: 79decbb40d93f0798189d4a131197db132549f1c diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.md b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.md index 4200532726..5f76baf33f 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.md @@ -1,9 +1,9 @@ # RFC: Drop unused session lineage metadata -English | [中文](2026-06-20-drop-unused-session-lineage.zh.md) - Status: rejected — `parentSession` is part of the documented fork/sub-agent seam and is already preserved by the agent/session resume path. The field is future-facing, but it is not accidental dead state. +English | [中文](2026-06-20-drop-unused-session-lineage.zh.md) + ## Problem `SessionHeader.parentSession` records the session a new session was forked from. It is defined in `dsh-session`, preserved by persistence backends, copied through resume, documented as lineage metadata, and covered by round-trip tests. The repo has no production fork UI or sub-agent flow that reads it. The planned sub-agent/fork seam is still a TODO, so the field is currently stored future shape. diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md index 1524987111..79decbb40d 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md @@ -1,9 +1,9 @@ -# RFC:移除未使用的会话血缘元数据 +# RFC: 移除未使用的会话血缘元数据 + +Status: rejected — `parentSession` is part of the documented fork/sub-agent seam and is already preserved by the agent/session resume path. The field is future-facing, but it is not accidental dead state. [English](2026-06-20-drop-unused-session-lineage.md) | 中文 -Status: rejected — `parentSession` 是已文档化的 fork/subagent seam 的一部分,且已被 agent(智能体)/session 恢复路径保留。该字段面向未来,但并非意外的死状态。 - ## 问题 `SessionHeader.parentSession` 记录新会话从哪个会话 fork 而来。它在 `dsh-session` 中定义,被持久化后端保留,在恢复流程中复制,作为血缘元数据被文档记录,并有往返测试覆盖。然而仓库中没有任何生产环境的 fork UI 或 subagent 流程读取它。计划中的 subagent/fork seam 仍是 TODO,因此该字段目前只是预存的未来形状。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml index 8442da7f7e..adb3407f9f 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-fold-session-persistence-interface.md: 695cd679c67f3e0a9f901c671c33e9507ecbe279 -2026-06-20-fold-session-persistence-interface.zh.md: 38f79f833fb5d95e4d9f392de627ee16b17cb997 +2026-06-20-fold-session-persistence-interface.md: 3e9bb277ccd0b6319081cd1aac289db764f41e58 +2026-06-20-fold-session-persistence-interface.zh.md: 13a8945fcaa5529f6d4dc156b0dc1016ab6da62d diff --git a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.md b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.md index 695cd679c6..3e9bb277cc 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.md +++ b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.md @@ -1,9 +1,9 @@ # RFC: Fold the persistence interface into dsh-session -English | [中文](2026-06-20-fold-session-persistence-interface.zh.md) - Status: rejected — the separate persistence interface package is the intended modular capability seam for durable backends. Folding it into `dsh-session` would reduce package count at the cost of a cleaner backend boundary. +English | [中文](2026-06-20-fold-session-persistence-interface.zh.md) + ## Problem `dsh-session-persistence` is an interface package whose main concepts are already owned by `dsh-session`: `SessionHeader`, `SessionEvent`, `SessionId`, `session/event`, and `session/flush`. The package adds the abstract `SessionPersistence` service, the shared write coordinator, and contract helpers. Backend packages depend on it, and `agent-loop` has to optionally find a sibling service for resume. diff --git a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md index 38f79f833f..13a8945fca 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md @@ -1,4 +1,4 @@ -# RFC:将持久化接口合并进 dsh-session +# RFC: 将持久化接口合并进 dsh-session Status: rejected — the separate persistence interface package is the intended modular capability seam for durable backends. Folding it into `dsh-session` would reduce package count at the cost of a cleaner backend boundary. diff --git a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml index 3af32eacdd..83244e5741 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-generic-tool-rendering.md: 07102ed3b12d7f587b1d12f0e240c1202a2e1cdd -2026-06-20-generic-tool-rendering.zh.md: d2c8c745f0ac04a01eb72b50fd1b63cb655afe36 +2026-06-20-generic-tool-rendering.md: 77d06968a24211835d1ff5db2541efdeb8227878 +2026-06-20-generic-tool-rendering.zh.md: ab032864a5304d6781d990d1f805fe9d280c1655 diff --git a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.md b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.md index 07102ed3b1..77d06968a2 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.md +++ b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.md @@ -1,9 +1,9 @@ # RFC: Collapse tool-owned UI presentation -English | [中文](2026-06-20-generic-tool-rendering.zh.md) - Status: rejected — tool-owned presentation should wait for more real tools before being generalized or deleted. Bash and ACP currently need the existing richer presentation path. +English | [中文](2026-06-20-generic-tool-rendering.zh.md) + ## Problem Tools can define `presentCall()` and `presentResult()` callbacks that return `ToolCallPresentation`, `ToolResultPresentation`, and optional `ToolTerminal` fields. The code itself flags the design as muddy: title, kind, raw input, content, terminal cwd, terminal output, exit code, and signal grew incrementally into a bag of optional fields. ACP then maintains pending call state to pair a result with the original args, creates replay-only presenters on `session/load`, and maps terminal subfields into Zed-specific `_meta`. `dsh-tool-bash` even parses exit status back out of rendered text because the pure replay-safe presenter no longer has the structured `BashRunResult`. diff --git a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md index d2c8c745f0..ab032864a5 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md @@ -1,9 +1,9 @@ -# RFC:收拢工具自有的 UI 展示逻辑 - -[English](2026-06-20-generic-tool-rendering.md) | 中文 +# RFC: 收拢工具自有的 UI 展示逻辑 Status: rejected — tool-owned presentation should wait for more real tools before being generalized or deleted. Bash and ACP currently need the existing richer presentation path. +[English](2026-06-20-generic-tool-rendering.md) | 中文 + ## 问题 工具可以定义 `presentCall()` 和 `presentResult()` 回调,返回 `ToolCallPresentation`、`ToolResultPresentation` 以及可选的 `ToolTerminal` 字段。代码本身就标记了这个设计的混乱:title、kind、raw input、content、terminal cwd、terminal output、exit code 和 signal 逐步增长为一堆可选字段。ACP(Agent Client Protocol)随后维护 pending call 状态以将 result 与原始 args 配对,在 `session/load` 时创建仅用于回放的 presenter,并将 terminal 子字段映射为 Zed 特有的 `_meta`。`dsh-tool-bash` 甚至从渲染后的文本中反向解析退出状态,因为纯回放安全的 presenter 已经拿不到结构化的 `BashRunResult`。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml index a944072e9f..96425f0390 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-retire-mid-turn-steering.md: bf78125ec175aa9152789bdccd1f8e8a16863a5b -2026-06-20-retire-mid-turn-steering.zh.md: a56e112df37bdeb75ca808f76beabe1fec8b1b7b +2026-06-20-retire-mid-turn-steering.md: 2c4d686942d2bfa8016bb60d55624dc59a933c1a +2026-06-20-retire-mid-turn-steering.zh.md: 2196d7d1d1f1bff39e8e0f03cf9910ab41434d2a diff --git a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.md b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.md index bf78125ec1..2c4d686942 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.md +++ b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.md @@ -1,9 +1,9 @@ # RFC: Retire mid-turn steering -English | [中文](2026-06-20-retire-mid-turn-steering.zh.md) - Status: rejected — mid-turn steering is an intentional agent capability for between-step user/plugin input and future goal/loop workflows. It is complexity with a product direction, not an accidental duplicate of `send()`. +English | [中文](2026-06-20-retire-mid-turn-steering.zh.md) + ## Problem The agent exposes two user-message paths that look close but have different lifecycle semantics: `send()` queues a normal user turn, while `steer()` injects a message between steps of the currently running turn and falls back to `send()` when idle. That distinction leaks through the whole stack: `Agent.steer()` is public API, the session log has a durable `steering/message` event, the agent event taxonomy has `agent/steering`, the loop maintains a steering FIFO beside the queued-message FIFO, cancellation clears both queues, and `deriveMessages()` has to render steering as a tagged synthetic user message rather than a normal prompt. diff --git a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md index a56e112df3..2196d7d1d1 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md @@ -1,9 +1,9 @@ -# RFC:移除轮次中途引导 - -[English](2026-06-20-retire-mid-turn-steering.md) | 中文 +# RFC: 移除轮次中途引导 Status: rejected — mid-turn steering is an intentional agent capability for between-step user/plugin input and future goal/loop workflows. It is complexity with a product direction, not an accidental duplicate of `send()`. +[English](2026-06-20-retire-mid-turn-steering.md) | 中文 + ## 问题 agent(智能体)暴露了两条用户消息路径,外观相近但生命周期语义不同:`send()` 将一条普通用户轮次排入队列,而 `steer()` 在当前运行轮次的步骤之间注入一条消息,空闲时则回退为 `send()`。这一区分贯穿整个栈:`Agent.steer()` 是公开 API;会话日志有持久化的 `steering/message` 事件;agent 事件分类体系有 `agent/steering`;agent loop(智能体循环)在排队消息 FIFO 之外还维护一个 steering FIFO;取消操作需要清空两个队列;`deriveMessages()` 必须将 steering 渲染为带标签的合成用户消息,而非普通提示词。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml index 57044817c0..b3e62c79cd 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-single-session-acp-bridge.md: b7b52ca4df2d118358303745f4484e3e40a242b3 -2026-06-20-single-session-acp-bridge.zh.md: bd287f79475433e4d5e502ef30abd5d14410e633 +2026-06-20-single-session-acp-bridge.md: 8aa8f5d605154f697086dd5d432bbe9bd79c5dcd +2026-06-20-single-session-acp-bridge.zh.md: a056bc5acfab9d48259670170a964e8358df866c diff --git a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.md b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.md index b7b52ca4df..8aa8f5d605 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.md +++ b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.md @@ -1,9 +1,9 @@ # RFC: Return the ACP bridge to one live session per connection -English | [中文](2026-06-20-single-session-acp-bridge.zh.md) - Status: rejected — Zed is the current target ACP client and its ACP implementation is explicitly multi-session: it stores live sessions in a `HashMap<SessionId, AcpSession>`, tracks `pending_sessions`, joins concurrent loads for the same id, and tests close-during-load behavior. +English | [中文](2026-06-20-single-session-acp-bridge.zh.md) + ## Problem The ACP bridge now supports multiple live sessions on one JSON-RPC connection. That capability brings multi-entry session maps, reverse session/agent lookups, per-session prompt state, loading ids, demux for every event, cross-session teardown, and isolation concerns for future permission prompts and background tasks. The older [multi-session ACP proposal](../../implemented/feature/2026-06-14-acp-multi-session.md) still tracks the unfinished permission-ownership piece; this RFC is the competing simplification path. diff --git a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md index bd287f7947..a056bc5acf 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md @@ -1,9 +1,9 @@ -# RFC:将 ACP 桥接恢复为每连接一个活跃会话 +# RFC: 将 ACP 桥接恢复为每连接一个活跃会话 + +Status: rejected — Zed is the current target ACP client and its ACP implementation is explicitly multi-session: it stores live sessions in a `HashMap<SessionId, AcpSession>`, tracks `pending_sessions`, joins concurrent loads for the same id, and tests close-during-load behavior. [English](2026-06-20-single-session-acp-bridge.md) | 中文 -Status: rejected — Zed 是当前目标 ACP 客户端,其 ACP 实现明确支持多会话:它将活跃会话存储在 `HashMap<SessionId, AcpSession>` 中,跟踪 `pending_sessions`,对同一 id 的并发加载进行合并,并测试加载期间关闭的行为。 - ## 问题 ACP(Agent Client Protocol)桥接现在支持在一条 JSON-RPC 连接上承载多个活跃会话。这一能力带来了多条目会话映射、反向会话/agent(智能体)查找、逐会话的 prompt 状态、加载中 id、每条事件的解复用、跨会话拆除,以及未来权限提示与后台任务的隔离问题。较早的[多会话 ACP 提案](../../implemented/feature/2026-06-14-acp-multi-session.md)仍在追踪未完成的权限归属部分;本 RFC 是与之竞争的简化路径。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml index 19a66353c7..1c341c252c 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-06-20-truncate-interrupted-turns.md: e17cb20f0185fe5d47d0a5ca18b7a389951fbadd -2026-06-20-truncate-interrupted-turns.zh.md: 48aeae650f867fb4629db33a448dd6cbaea60ae0 +2026-06-20-truncate-interrupted-turns.md: dd8475771fcd9fdd0910bd37480a50679e87911c +2026-06-20-truncate-interrupted-turns.zh.md: 7fcd7292c8c53ebf4d784cdb79a1be58960f763c diff --git a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.md b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.md index e17cb20f01..dd8475771f 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.md +++ b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.md @@ -1,9 +1,9 @@ # RFC: Truncate interrupted final turns on load -English | [中文](2026-06-20-truncate-interrupted-turns.zh.md) - Status: rejected — a single turn can contain substantial real work, including many steps and large tool output. Preserving interrupted turns is preferable to silently dropping that tail on load. +English | [中文](2026-06-20-truncate-interrupted-turns.zh.md) + ## Problem The current persistence contract preserves a final turn that was durably written but never closed. On load, `interruptedTurnClosers()` scans the tail, synthesizes error `tool/result` events for unanswered tool calls, appends a `step/end` when a step is open, appends `turn/end { kind: 'interrupted' }`, and asks the backend to durably commit that repair. The coordinator, JSONL backend, SQLite backend, session event vocabulary, invariants, docs, and tests all model this synthetic close path. diff --git a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md index 48aeae650f..7fcd7292c8 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md @@ -1,4 +1,4 @@ -# RFC:加载时截断被中断的最终轮次 +# RFC: 加载时截断被中断的最终轮次 Status: rejected — a single turn can contain substantial real work, including many steps and large tool output. Preserving interrupted turns is preferable to silently dropping that tail on load. diff --git a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml index 915d56d0e8..cd0677dac6 100644 --- a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-04-prune-unimplemented-subagent-vocabulary.md: 3c86f11564d85b423fe59d784c6bf69959fb3907 -2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md: 84ff6f15ff2c9b3a13240997ab3c7b5cf2ab7263 +2026-07-04-prune-unimplemented-subagent-vocabulary.md: 1621bc1feee8bf98478242f002d9d1dca16878f5 +2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md: b26ffee4764cd5a5937ef0436fa30c7c0eeba87a diff --git a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md index 3c86f11564..1621bc1fee 100644 --- a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md +++ b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md @@ -1,9 +1,9 @@ # RFC: Prune the unimplemented subagent seam vocabulary -English | [中文](2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md) - Status: rejected — the deferred capability vocabulary (`outputSchema`/`structured`, `toolFilter`, `sendMessage`/`resume`) is intentionally reserved surface: the seam advertises the full intended contract ahead of its implementations by design, so providers and consumers grow into a stable shape rather than re-negotiating it per capability. The consumer-evidence analysis below stands as the record of what is currently unimplemented. +English | [中文](2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md) + ## Problem The [subagent seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) shipped a two-tier capability design: start-time capability flags checked by the service, and optional runtime methods on `SubagentRun`. Three start-time features and both optional runtime methods have zero implementations and zero callers: diff --git a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md index 84ff6f15ff..b26ffee476 100644 --- a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md +++ b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md @@ -1,9 +1,9 @@ -# RFC:裁剪未实现的 subagent seam 词汇 - -[English](2026-07-04-prune-unimplemented-subagent-vocabulary.md) | 中文 +# RFC: 裁剪未实现的 subagent seam 词汇 Status: rejected — the deferred capability vocabulary (`outputSchema`/`structured`, `toolFilter`, `sendMessage`/`resume`) is intentionally reserved surface: the seam advertises the full intended contract ahead of its implementations by design, so providers and consumers grow into a stable shape rather than re-negotiating it per capability. The consumer-evidence analysis below stands as the record of what is currently unimplemented. +[English](2026-07-04-prune-unimplemented-subagent-vocabulary.md) | 中文 + ## 问题 [subagent seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 交付了一套两层能力设计:启动时由服务检查的能力 flag,以及 `SubagentRun` 上的可选运行时方法。三个启动时特性和两个可选运行时方法的实现数与调用数均为零: diff --git a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml index 98bc1e4bab..b6d3903ddd 100644 --- a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-12-collapse-workflow-to-foreground-core.md: 78b67c10ac39fddaf4ea76ca90d5cbf760fe5866 -2026-07-12-collapse-workflow-to-foreground-core.zh.md: 28b0af0a70110d39572fafac521a555c62ebb3f5 +2026-07-12-collapse-workflow-to-foreground-core.md: eaf8a4a22766e06b743a7b91d2a607eb6c8e67d9 +2026-07-12-collapse-workflow-to-foreground-core.zh.md: 4b1f4ebbec852386ca4577a38a9bd41b7529e500 diff --git a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.md b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.md index 78b67c10ac..eaf8a4a227 100644 --- a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.md +++ b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.md @@ -1,9 +1,9 @@ # RFC: Collapse workflows to the exercised foreground core -English | [中文](2026-07-12-collapse-workflow-to-foreground-core.zh.md) - Status: rejected — Workflow progress is an intentional observation surface; make it useful through a consumer instead of deleting it. +English | [中文](2026-07-12-collapse-workflow-to-foreground-core.zh.md) + ## Problem The workflow capability executes foreground JavaScript that composes subagents, but it also carries an unconsumed progress-observation system. No production listener subscribes to any of the six `workflow/*` events; listeners exist only in workflow tests. Nevertheless the seam defines run/phase/agent outcome payloads, the worker sends phase/log/agent lifecycle protocol messages, the host forwards them through a `liveAgents` pairing ledger, and the engine maintains run ids solely to correlate those notifications. diff --git a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md index 28b0af0a70..4b1f4ebbec 100644 --- a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md +++ b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md @@ -1,9 +1,9 @@ -# RFC:将工作流收缩至已使用的前台核心 - -[English](2026-07-12-collapse-workflow-to-foreground-core.md) | 中文 +# RFC: 将工作流收缩至已使用的前台核心 Status: rejected — Workflow progress is an intentional observation surface; make it useful through a consumer instead of deleting it. +[English](2026-07-12-collapse-workflow-to-foreground-core.md) | 中文 + ## 问题 工作流能力执行前台 JavaScript 来编排 subagent,但它同时携带了一套无人消费的进度观测系统。没有任何生产环境的监听器订阅六个 `workflow/*` 事件中的任何一个;监听器仅存在于工作流测试中。尽管如此,seam 定义了 run/phase/agent outcome 载荷,worker 发送 phase/log/agent 生命周期协议消息,host 通过一个 `liveAgents` 配对账本转发它们,引擎维护 run id 仅仅是为了关联这些通知。 diff --git a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml index a9c24674bf..0c7d9feb75 100644 --- a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-12-prune-unused-skill-registry-surface.md: 3e8c009871c3d609612b4a01edc2048ddedfad0d -2026-07-12-prune-unused-skill-registry-surface.zh.md: deaea2ca53d4ed2ac5141013f969f621d3202875 +2026-07-12-prune-unused-skill-registry-surface.md: 5b90deca8681373b2cc2befa3ab341084f924a3d +2026-07-12-prune-unused-skill-registry-surface.zh.md: 7b0e24f49688ed61f2ac4bff93b4c3f85117a170 diff --git a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.md b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.md index 3e8c009871..5b90deca86 100644 --- a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.md +++ b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.md @@ -1,9 +1,9 @@ # RFC: Prune unused skill registry surface -English | [中文](2026-07-12-prune-unused-skill-registry-surface.zh.md) - Status: rejected — Direct runtime skill registration is an intentional extension path for third-party plugins. +English | [中文](2026-07-12-prune-unused-skill-registry-surface.zh.md) + ## Problem The skill service's embedded-runtime subsystem has zero production caller of `ctx.skills.register()`. It adds a reserved `runtime` provider name, a runtime map/rank/source, duplicate policy, a second revision in cache keys, normalization, disposers, and tests alongside the provider seam every shipped skill already uses. `SkillSummary.whenToUse` and candidate/definition `path` are parsed and copied but never read by a production consumer: the model catalog renders name/description, resource loading uses `resourceBase`, and providers own their locator. The deliberately open `metadata` extension point stays. diff --git a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md index deaea2ca53..7b0e24f496 100644 --- a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md +++ b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md @@ -1,9 +1,9 @@ -# RFC:裁剪 skill 注册表中未使用的接口 - -[English](2026-07-12-prune-unused-skill-registry-surface.md) | 中文 +# RFC: 裁剪 skill 注册表中未使用的接口 Status: rejected — Direct runtime skill registration is an intentional extension path for third-party plugins. +[English](2026-07-12-prune-unused-skill-registry-surface.md) | 中文 + ## 问题 skill(技能)服务的嵌入式运行时子系统中,`ctx.skills.register()` 没有任何生产调用方。它引入了一个保留的 `runtime` 提供方名称、一套运行时 map/rank/source、重复策略、缓存键中的第二个 revision、规范化逻辑、dispose(资源释放)器以及相应测试——而所有已交付的 skill 都只使用提供方 seam。`SkillSummary.whenToUse` 和 candidate/definition 的 `path` 被解析和复制,但没有任何生产消费方读取它们:模型目录只渲染 name/description,资源加载使用 `resourceBase`,提供方自行管理其定位器。有意开放的 `metadata` 扩展点保留不动。