diff --git a/.github/windows-concurrency/ancestor-copy-admission.json b/.github/windows-concurrency/ancestor-copy-admission.json deleted file mode 100644 index 1276933c99..0000000000 --- a/.github/windows-concurrency/ancestor-copy-admission.json +++ /dev/null @@ -1,24 +0,0 @@ -[ - { - "package": "reasonix/internal/runtime/delegation", - "tests": [ - "TestAncestorCopyAdmissionCoversUnpublishedRun", - "TestAncestorCopyAdmissionCoversUnpublishedRun/continue_then_continue", - "TestAncestorCopyAdmissionCoversUnpublishedRun/continue_then_legacy", - "TestAncestorCopyAdmissionCoversUnpublishedRun/legacy_then_continue", - "TestAncestorCopyAdmissionCoversUnpublishedRun/legacy_then_legacy", - "TestAncestorCopyAdmissionAllowsDifferentParents", - "TestAncestorCopyAdmissionReleasesAbandonedPreparation", - "TestAncestorCopyAdmissionReleasesAfterInvalidCopy", - "TestAncestorCopyAdmissionAllowsDifferentSources", - "TestAncestorCopyAdmissionUsesNearestSourceIdentity", - "TestAncestorCopyAdmissionReleasesAfterBusyCurrentReference", - "TestTaskAncestorCopyAdmissionBeforeRunningMetadata", - "TestTaskAncestorCopyAdmissionBeforeRunningMetadata/continue_from", - "TestTaskAncestorCopyAdmissionBeforeRunningMetadata/fork_from", - "TestTaskAncestorCopyAdmissionReleasesUnstartedBackground", - "TestTaskAncestorCopyAdmissionReleasesUnstartedBackground/continue_from", - "TestTaskAncestorCopyAdmissionReleasesUnstartedBackground/fork_from" - ] - } -] diff --git a/.github/windows-concurrency/carried-proof-file-state.json b/.github/windows-concurrency/carried-proof-file-state.json deleted file mode 100644 index 34a9c2dfba..0000000000 --- a/.github/windows-concurrency/carried-proof-file-state.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "package": "reasonix/internal/runtime/agent", - "tests": [ - "TestCarriedProofInvalidatesPermissionChange", - "TestCarriedProofFileStateCompatibility", - "TestCarriedProofFileStateCompatibility/legacy_file", - "TestCarriedProofFileStateCompatibility/legacy_absent", - "TestCarriedProofFileStateCompatibility/future", - "TestCarriedProofFileStateCompatibility/current_file", - "TestCarriedProofFileStateCompatibility/current_absent", - "TestCarriedProofRejectsDirectoryState", - "TestCarriedProofStandsOnlyForUnchangedContent", - "TestCarriedProofSeesADeletion" - ] - }, - { - "package": "reasonix/internal/assembly/boot", - "tests": [ - "TestEffectCarriedProofTracksFileState", - "TestEffectCarriedProofTracksFileState/unchanged", - "TestEffectCarriedProofTracksFileState/content", - "TestEffectCarriedProofTracksFileState/mode" - ] - } -] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 87072aee91..e48c4a639a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -170,23 +170,6 @@ jobs: shell: pwsh run: Get-CimInstance Win32_Processor | Select-Object -ExpandProperty Name - - name: test (Windows concurrency contracts) - if: env.RUN_STEPS == 'true' && runner.os == 'Windows' && github.event_name == 'pull_request' - timeout-minutes: 5 - shell: bash - run: | - node --test scripts/windows-concurrency-tests.test.mjs - node scripts/windows-concurrency-tests.mjs "$RUNNER_TEMP/concurrency-windows.jsonl" - - - name: upload Windows concurrency inventory - if: always() && env.RUN_STEPS == 'true' && runner.os == 'Windows' && github.event_name == 'pull_request' - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 - with: - name: concurrency-windows-${{ github.run_attempt }} - path: ${{ runner.temp }}/concurrency-windows.jsonl - if-no-files-found: error - retention-days: 7 - - name: test if: env.RUN_STEPS == 'true' && runner.os != 'Windows' env: @@ -196,35 +179,6 @@ jobs: REASONIX_RELEASE_CACHE_GUARD: "1" run: go test ./... - - name: test (Windows subagent status admission) - if: env.RUN_STEPS == 'true' && runner.os == 'Windows' && github.event_name == 'pull_request' - timeout-minutes: 5 - shell: bash - run: | - set -o pipefail - go test -count=1 -timeout=3m -json -run '^TestSubagent(PersistedStatusAdmission|UnknownStatusStillReadableForDiagnosis)$' ./internal/runtime/delegation | tee "$RUNNER_TEMP/subagent-status-admission.jsonl" - jq -se ' - [.[] | select(.Test == null and .Action == "pass") | .Package] as $packages | - [.[] | select(.Test != null and .Action == "pass") | .Test] as $tests | - ["future-paused", "missing", "empty", "COMPLETED", "completed", "cancelled", "failed", "interrupted", "running"] as $states | - ["continue", "copy", "ancestor", "legacy_ancestor", "current_copy"] as $routes | - (["TestSubagentPersistedStatusAdmission", "TestSubagentUnknownStatusStillReadableForDiagnosis"] + - [$states[] | "TestSubagentPersistedStatusAdmission/" + .] + - [$states[] as $state | $routes[] | "TestSubagentPersistedStatusAdmission/" + $state + "/" + .]) as $required | - all(.[]; .Action != "skip" and .Action != "fail") and - (["reasonix/internal/runtime/delegation"] - $packages | length) == 0 and - ($required - $tests | length) == 0 - ' "$RUNNER_TEMP/subagent-status-admission.jsonl" - - - name: upload Windows subagent status admission inventory - if: always() && env.RUN_STEPS == 'true' && runner.os == 'Windows' && github.event_name == 'pull_request' - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 - with: - name: subagent-status-admission-windows-${{ github.run_attempt }} - path: ${{ runner.temp }}/subagent-status-admission.jsonl - if-no-files-found: ignore - retention-days: 7 - - name: test (Windows composition links) if: env.RUN_STEPS == 'true' && runner.os == 'Windows' && github.event_name == 'pull_request' timeout-minutes: 5 @@ -307,34 +261,17 @@ jobs: [.[] | select(.Test == null and .Action == "pass") | .Package] as $passed | [.[] | select(.Test != null and .Action == "pass") | .Test] as $tests | (["reasonix/internal/runtime/isolation", "reasonix/internal/platform/worktree", "reasonix/internal/state/mutation"] - $passed | length) == 0 and - (["TestResultOperationUsesCrossProcessOwnership", - "TestActualResultOperationHoldsOwnershipThroughWriteAndCleanup/restore", - "TestActualResultOperationHoldsOwnershipThroughWriteAndCleanup/remove", - "TestApplyPathsWithUntrustedModesPreservesTheIndex/content", - "TestApplyPathsWithUntrustedModesPreservesTheIndex/source_index_mode", - "TestApplyPathsWithUntrustedModesPreservesTheIndex/candidate_mode", - "TestApplyPathsWithUntrustedModesPreservesTheIndex/candidate_type", - "TestApplyPathsEmulatedLinksUseSnapshotFilters", - "TestHeldPathsCoverOnlyTheSameFileAcrossCaseSpellings", + (["TestHeldPathsCoverOnlyTheSameFileAcrossCaseSpellings", "TestLegacyWaitDoesNotConsumeExecutionCapacity"] - $tests | length) == 0 ' "$RUNNER_TEMP/isolation-owners.jsonl" jq -se ' . as $events | {"reasonix/internal/platform/worktree": [ - "TestApplyPathsRejectsRedirectedAncestors", - "TestApplyPathsRejectsRedirectedAncestors/outside_delete", - "TestApplyPathsRejectsRedirectedAncestors/inside_delete", - "TestApplyPathsRejectsRedirectedAncestors/dangling_delete", - "TestApplyPathsRejectsRedirectedAncestors/outside_write", - "TestApplyPathsRejectsRedirectedAncestors/inside_write", - "TestApplyPathsRejectsRedirectedAncestors/regular_parent", - "TestApplyPathsRejectsRedirectedAncestors/unchanged", - "TestApplyPathsRejectsRedirectedAncestors/missing_creation", "TestWriteChangesRejectsRedirectedDeletion", - "TestWriteChangesUnlinksLeafDirectoryLink", - "TestWholeWorkspaceApplyPreservesFileToDirectoryTransition"], + "TestWriteChangesUnlinksLeafDirectoryLink" + ], "reasonix/internal/runtime/isolation": [ - "TestApplyToolRetainsResultAfterAncestorReplacement"]} | + ]} | to_entries | all(.[]; . as $package | ([ $events[] | select(.Package == $package.key and .Test == null and (.Action == "pass" or .Action == "fail" or .Action == "skip")) ] | @@ -354,60 +291,15 @@ jobs: if-no-files-found: ignore retention-days: 7 - - name: test (Windows background resource owners) - if: env.RUN_STEPS == 'true' && runner.os == 'Windows' && github.event_name == 'pull_request' - timeout-minutes: 25 - shell: bash - run: | - set -o pipefail - go test -count=1 -p 2 -timeout=18m -json ./internal/tools/jobs/... ./internal/runtime/delegation/... | tee "$RUNNER_TEMP/background-resources.jsonl" | - jq -rj --unbuffered 'select(.Action == "output" and .Test == null) | .Output' - jq -se ' - [.[] | select(.Test == null and .Action == "pass") | .Package] as $packages | - [.[] | select(.Test != null and .Action == "pass") | .Test] as $tests | - (["reasonix/internal/tools/jobs", "reasonix/internal/runtime/delegation"] - $packages | length) == 0 and - (["TestJobFinalizationCoversInvokedAndUninvoked/success", - "TestJobFinalizationCoversInvokedAndUninvoked/error", - "TestJobFinalizationCoversInvokedAndUninvoked/panic", - "TestJobFinalizationCoversInvokedAndUninvoked/closed", - "TestJobFinalizationCoversInvokedAndUninvoked/invalid_session", - "TestJobFinalizationCoversInvokedAndUninvoked/invalid_kind", - "TestJobFinalizationFailuresAttemptAllCallbacksAndKeepCauses/invoked", - "TestJobFinalizationFailuresAttemptAllCallbacksAndKeepCauses/uninvoked", - "TestJobFinalizationPrecedesCompletionPublication", - "TestJobFinalizationCloseBetweenPublicationAndLaunch", - "TestJobFinalizationWaitsForClosureAfterLogicalCancellation", - "TestBackgroundNoLaunchFinalizesOwnedResources/task/closed_manager", - "TestBackgroundNoLaunchFinalizesOwnedResources/task/invalid_session", - "TestBackgroundNoLaunchFinalizesOwnedResources/fleet/closed_manager", - "TestBackgroundNoLaunchFinalizesOwnedResources/fleet/invalid_session"] - $tests | length) == 0 - ' "$RUNNER_TEMP/background-resources.jsonl" - - - name: upload Windows background resource inventory - if: always() && env.RUN_STEPS == 'true' && runner.os == 'Windows' && github.event_name == 'pull_request' - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 - with: - name: background-resources-windows-${{ github.run_attempt }} - path: ${{ runner.temp }}/background-resources.jsonl - if-no-files-found: ignore - retention-days: 7 - - name: test (Windows delegated Goal usage scope) if: env.RUN_STEPS == 'true' && runner.os == 'Windows' && github.event_name == 'pull_request' shell: bash run: | set -o pipefail - go test -count=1 -timeout=3m -json -run '^Test(UsageScope.*|DelegatedUsageKeepsGoalOwner|EffectDelegatedUsageKeepsGoalOwner)$' ./internal/contract/event ./internal/session/control ./internal/assembly/boot | tee "$RUNNER_TEMP/goal-usage-scope.jsonl" + go test -count=1 -timeout=3m -json -run '^Test(UsageScope.*)$' ./internal/contract/event ./internal/session/control ./internal/assembly/boot | tee "$RUNNER_TEMP/goal-usage-scope.jsonl" jq -se ' - ["TestUsageScopePreservesCapturedOwnerAndWire", "TestUsageScopeKeepsEarlierEventOwner", - "TestUsageScopeWithoutCapability", "TestDelegatedUsageKeepsGoalOwner", - "TestDelegatedUsageKeepsGoalOwner/chat_to_goal", "TestDelegatedUsageKeepsGoalOwner/replaced_goal", - "TestDelegatedUsageKeepsGoalOwner/cleared_goal", "TestDelegatedUsageKeepsGoalOwner/resumed_goal", - "TestDelegatedUsageKeepsGoalOwner/same_goal_next_turn", "TestDelegatedUsageKeepsGoalOwner/between_turns", - "TestDelegatedUsageKeepsGoalOwner/nested_after_replacement", "TestEffectDelegatedUsageKeepsGoalOwner", - "TestEffectDelegatedUsageKeepsGoalOwner/chat_to_goal", "TestEffectDelegatedUsageKeepsGoalOwner/replaced_goal", - "TestEffectDelegatedUsageKeepsGoalOwner/nested_chat_to_goal", "TestEffectDelegatedUsageKeepsGoalOwner/same_goal", - "TestEffectDelegatedUsageKeepsGoalOwner/completed_before_goal"] as $required | + ["TestUsageScopeKeepsEarlierEventOwner", + "TestUsageScopeWithoutCapability" ] as $required | [.[] | select(.Test != null and .Action == "pass") | .Test] as $passed | [.[] | select(.Test == null and .Action == "pass") | .Package] as $packages | all(.[]; .Action != "fail" and .Action != "skip") and @@ -511,10 +403,7 @@ jobs: [.[] | select(.Test != null and .Action == "pass") | .Test] as $tests | all(.[]; .Action != "skip" and .Action != "fail") and (["reasonix/internal/runtime/agent", "reasonix/internal/runtime/coordinator", "reasonix/internal/assembly/boot"] - $packages | length) == 0 and - (["TestPreparedRootBudgetLifetime", "TestPreparedRootBudgetLifetime/continuation", - "TestPreparedRootBudgetLifetime/new_scope", "TestPreparedRootBudgetLifetime/new_task", - "TestPreparedRootBudgetLifetime/reset", "TestPreparedRootBudgetLifetime/new_session", - "TestPreparedRootBudgetProjectionAndPreservedTurn", "TestCoordinatorRootBudgetRoutes", + (["TestCoordinatorRootBudgetRoutes", "TestCoordinatorRootBudgetRoutes/raw", "TestCoordinatorRootBudgetRoutes/tool_planner", "TestCoordinatorRootBudgetRoutes/failure_fallback", "TestCoordinatorRootBudgetRoutes/plan_only_continuation", "TestCoordinatorRootBudgetRoutes/approval_declined_continuation", "TestCoordinatorRootBudgetRoutes/approval_allowed", @@ -578,10 +467,8 @@ jobs: "TestRootWallBudgetReachesDelegatedAgents/context", "TestRootWallBudgetReachesDelegatedAgents/unconfigured", "TestRootWallBudgetReachesDelegatedAgents/explicit_zero", "TestRootWallBudgetContinuationAndReset", "TestRootWallBudgetContinuationAndReset/continuation", "TestRootWallBudgetContinuationAndReset/new_task", - "TestRootWallBudgetContinuationAndReset/reset", "TestRootWallBudgetContinuationAndReset/override", - "TestRootWallBudgetProjectionKeepsJobDeadline", "TestEffectRootWallBudgetReachesManagedJobs", - "TestEffectRootWallBudgetReachesManagedJobs/task", "TestEffectRootWallBudgetReachesManagedJobs/capability", - "TestEffectRootWallBudgetReachesManagedJobs/fleet"] - $tests | length) == 0 + "TestRootWallBudgetContinuationAndReset/reset", "TestRootWallBudgetContinuationAndReset/override" + ] - $tests | length) == 0 ' "$RUNNER_TEMP/root-wall-budget.jsonl" - name: upload Windows root wall budget inventory @@ -611,10 +498,7 @@ jobs: "TestRootTokenBudgetSurvivesNestedAndConcurrentChildren/nested", "TestRootTokenBudgetSurvivesNestedAndConcurrentChildren/siblings", "TestRootTokenBudgetSurvivesNestedAndConcurrentChildren/child_override", "TestRootTokenBudgetContinuationAndReset", "TestRootTokenBudgetContinuationAndReset/continuation", "TestRootTokenBudgetContinuationAndReset/new_task", - "TestRootTokenBudgetContinuationAndReset/reset", "TestRootTokenScopeAtomicAccountingAndJobCancellation", - "TestEffectRootTokenBudgetReachesDelegatedJobs", "TestEffectRootTokenBudgetReachesDelegatedJobs/foreground", - "TestEffectRootTokenBudgetReachesDelegatedJobs/foreground_capability", "TestEffectRootTokenBudgetReachesDelegatedJobs/background", - "TestEffectRootTokenBudgetReachesDelegatedJobs/background_capability", "TestEffectRootTokenBudgetReachesDelegatedJobs/background_fleet"] - $tests | length) == 0 + "TestRootTokenBudgetContinuationAndReset/reset" ] - $tests | length) == 0 ' "$RUNNER_TEMP/root-token-budget.jsonl" jq -se ' . as $events | @@ -628,8 +512,6 @@ jobs: "TestBudgetCountsKnownReportedTokens/negative_split", "TestBudgetCountsKnownReportedTokens/zero", "TestBudgetCountsKnownReportedTokens/negative", - "TestReportedTokensEnforceLocalCapOnInheritedRoot", - "TestReportedTokensFollowOriginalAuxiliaryRoot", "TestReportedTokenCountersSaturate"], "reasonix/internal/assembly/boot": [ "TestEffectReportedTotalTokenBudget", @@ -697,7 +579,7 @@ jobs: shell: bash run: | set -o pipefail - go test -count=1 -timeout=3m -json -run '^Test(HostStorageEnvironment|HostObjectStorage|HostExplicitStorageControls|DetachedStorageEnvironment|WorktreePreparationOwnsItsIndex|EffectIsolatedTaskOwnsGitStorage)$' ./internal/platform/gitcmd ./internal/platform/worktree ./internal/assembly/boot | tee "$RUNNER_TEMP/git-storage-environment.jsonl" + go test -count=1 -timeout=3m -json -run '^Test(HostStorageEnvironment|HostObjectStorage|HostExplicitStorageControls|DetachedStorageEnvironment)$' ./internal/platform/gitcmd ./internal/platform/worktree ./internal/assembly/boot | tee "$RUNNER_TEMP/git-storage-environment.jsonl" jq -se ' [.[] | select(.Test == null and .Action == "pass") | .Package] as $packages | [.[] | select(.Test != null and .Action == "pass") | .Test] as $tests | @@ -707,10 +589,6 @@ jobs: "TestDetachedStorageEnvironment", "TestDetachedStorageEnvironment/explicit_env", "TestDetachedStorageEnvironment/inherited_env", - "TestEffectIsolatedTaskOwnsGitStorage", - "TestEffectIsolatedTaskOwnsGitStorage/ambient_existing", - "TestEffectIsolatedTaskOwnsGitStorage/ambient_missing", - "TestEffectIsolatedTaskOwnsGitStorage/control", "TestHostExplicitStorageControls", "TestHostExplicitStorageControls/explicit_object_directory", "TestHostExplicitStorageControls/private_index", @@ -721,15 +599,8 @@ jobs: "TestHostStorageEnvironment", "TestHostStorageEnvironment/GIT_ALTERNATE_OBJECT_DIRECTORIES", "TestHostStorageEnvironment/GIT_INDEX_FILE", - "TestHostStorageEnvironment/GIT_OBJECT_DIRECTORY", - "TestWorktreePreparationOwnsItsIndex", - "TestWorktreePreparationOwnsItsIndex/candidate_ambient_existing", - "TestWorktreePreparationOwnsItsIndex/candidate_ambient_missing", - "TestWorktreePreparationOwnsItsIndex/candidate_control", - "TestWorktreePreparationOwnsItsIndex/delivery_ambient_existing", - "TestWorktreePreparationOwnsItsIndex/delivery_ambient_missing", - "TestWorktreePreparationOwnsItsIndex/delivery_control" - ] - $tests | length) == 0 + "TestHostStorageEnvironment/GIT_OBJECT_DIRECTORY" + ] - $tests | length) == 0 ' "$RUNNER_TEMP/git-storage-environment.jsonl" - name: upload Windows Git storage environment inventory @@ -816,11 +687,7 @@ jobs: [.[] | select(.Test != null and .Action == "pass") | .Test] as $tests | all(.[]; .Action != "skip" and .Action != "fail") and (["reasonix/internal/session/control", "reasonix/internal/assembly/boot"] - $packages | length) == 0 and - (["TestProfileRootBudgetLifetime", "TestProfileRootBudgetLifetime/new_task", - "TestProfileRootBudgetLifetime/same_scope", "TestProfileRootBudgetLifetime/new_scope", - "TestProfileRootBudgetLifetime/reset", "TestProfileRootBudgetLifetime/new_session", - "TestProfileRootBudgetLifetime/inherited", "TestProfileRootBudgetLifetime/context_zero", - "TestProfileBudgetPreparationUsesTurnAdmission", "TestEffectExplicitSkillRootBudget", + (["TestProfileBudgetPreparationUsesTurnAdmission", "TestEffectExplicitSkillRootBudget", "TestEffectExplicitSkillRootBudget/profile", "TestEffectExplicitSkillRootBudget/preview", "TestEffectExplicitSkillRootBudget/slash", "TestEffectExplicitSkillRootBudget/chips", "TestEffectExplicitSkillRootBudget/goal", "TestEffectExplicitSkillRootBudget/context_zero", @@ -883,8 +750,7 @@ jobs: "TestRootAuxiliaryTokenBudget/summary_missing", "TestRootAuxiliaryTokenBudget/summary_disabled", "TestRootAuxiliaryTokenBudget/diagnosis", "TestRootAuxiliaryTokenBudget/diagnosis_failed", "TestRootAuxiliaryTokenBudget/diagnosis_missing", "TestRootAuxiliaryTokenBudget/diagnosis_disabled", - "TestRootAuxiliaryManualCompactionOutsideRun", "TestRootAuxiliaryBudgetProjectionKeepsOldTask", - "TestEffectRootAuxiliarySummaryBudget", "TestEffectRootAuxiliarySummaryBudget/configured", + "TestRootAuxiliaryManualCompactionOutsideRun", "TestEffectRootAuxiliarySummaryBudget", "TestEffectRootAuxiliarySummaryBudget/configured", "TestEffectRootAuxiliarySummaryBudget/disabled", "TestEffectRootAuxiliarySummaryBudget/missing_usage"] - $tests | length) == 0 ' "$RUNNER_TEMP/root-auxiliary-budget.jsonl" @@ -974,11 +840,7 @@ jobs: "TestBoundedUsageObserverOwnsOneTerminal", "TestBoundedUsageObserverOwnsOneTerminal/reported", "TestBoundedUsageObserverOwnsOneTerminal/billed_failure", "TestBoundedUsageObserverOwnsOneTerminal/without_sink", "TestBoundedUsageObserverOwnsOneTerminal/missing", "TestBoundedUsageObserverOwnsOneTerminal/input_refused", - "TestRootBoundedReviewerBudget", "TestRootBoundedReviewerBudget/reported", - "TestRootBoundedReviewerBudget/billed_failure", "TestRootBoundedReviewerBudget/missing_usage", - "TestRootBoundedReviewerBudget/disabled", "TestRootBoundedReviewerBudget/no_emission", - "TestRootBoundedReviewerBudget/projected_job_context", "TestRootBoundedNestedBudgetChargesOnce", - "TestRootBoundedLateProjectionStaysWithOldTask", "TestEffectRootBoundedAdvisorBudget", + "TestEffectRootBoundedAdvisorBudget", "TestEffectRootBoundedAdvisorBudget/reported", "TestEffectRootBoundedAdvisorBudget/disabled", "TestEffectRootBoundedAdvisorBudget/missing_usage"] - $tests | length) == 0 ' "$RUNNER_TEMP/bounded-root-budget.jsonl" diff --git a/docs/CARRIED_PROOF_FILE_STATE.md b/docs/CARRIED_PROOF_FILE_STATE.md deleted file mode 100644 index 72712bf4fc..0000000000 --- a/docs/CARRIED_PROOF_FILE_STATE.md +++ /dev/null @@ -1,135 +0,0 @@ ---- -owner: @SivanCola -backup: @esengine -status: active -reviewed: 2026-10-28 ---- - -# Carried proof and file state / 恢复证明与文件状态 - -## Behavior / 行为 - -A pending Delivery change may carry verification, inspection and sign-off -across a Controller rebuild. Its fingerprint now includes regular-file bytes -and the full file mode reported by Go. Changing permissions without changing -bytes invalidates that carried proof and requires fresh evidence. - -Delivery 待完成修改可在 Controller 重建后保留验证、检查和签收证明。指纹现在同时 -绑定普通文件字节与 Go 返回的完整文件模式。只改权限、不改内容,也会使旧证明失效, -恢复后需要重新取得证据。 - -The existing content-version reader supplies the digest and detects observed -read changes. The proof owner additionally checks file identity, mode, size -and modification time around that read. It does not change permissions or -repair files. Absence has its own versioned fingerprint. - -既有内容版本读取器提供摘要并检测读取期间观察到的变化;证明 owner 另外核对读取 -前后的文件身份、模式、大小与修改时间。它不修改权限或修复文件。文件缺失使用独立 -的版本化指纹。 - -Every nonregular path returns an empty fingerprint and never reuses carried -proof. This includes a symlink to an otherwise regular file, as well as -directories and special files. A dangling symlink is not absence. - -The cost is fresh verification, inspection and sign-off after continuation or rebuild even -when a symlink and its target bytes have not changed. This invalidation does -not itself produce a separate warning. Existing tools can still collect fresh -evidence; tool permissions and normal completion rules are unchanged. - -所有非普通文件路径返回空指纹,均不复用携带的证明,包括指向普通文件的符号链接、 -目录与特殊文件;悬空链接不算文件缺失。即使链接及目标字节没有变化,继续执行或 -重建后也要重新验证、检查和签收,这是明确的复用成本;失效本身不会单独显示警告。 -仍可通过原工具收集新证据,不改变工具权限或正常完成规则。 - -## Persisted compatibility / 持久化兼容性 - -The existing `DeliveryCheckpoint.Proven.Paths` map remains a map of strings. -New values use the `file-state-v1:` prefix. No field, enum, RPC, configuration -or session format is added, and comparison does not rewrite the checkpoint. - -既有 `DeliveryCheckpoint.Proven.Paths` 仍为字符串映射,新值使用 `file-state-v1:` -前缀。不新增字段、枚举、RPC、配置或会话格式,比较过程不改写 checkpoint。 - -| Fingerprint | Current reader | Previous byte-only reader | -| --- | --- | --- | -| Legacy raw SHA-256 or `absent` | Reads Goal data; requires fresh proof | Retains its previous behavior | -| Current regular-file state | Reuses only matching observed state | Reads Goal data; mismatch requires fresh proof | -| Current absence | Reuses only actual absence | Mismatch requires fresh proof | -| Unknown future value | Mismatch requires fresh proof | Mismatch requires fresh proof | - -Legacy values cannot prove which permissions or file kind were checked. -They are deliberately not upgraded from current metadata: that would invent -past evidence. Existing goals and transcripts remain readable; after upgrade -or downgrade, a pending goal may need verification, inspection and sign-off again. - -旧值不能证明当时检查过哪些权限与文件类型,因此不会用当前元数据自动补成历史 -证据。既有 Goal 和会话仍可读取;升级或降级后,待完成 Goal 可能需要重新验证、 -检查与签收。新旧程序共存不等于已解决其他持久化写入协议问题。 - -## Evidence and limits / 验证与限制 - -The Boot regression uses real file tools, a real verification command and -production Goal persistence. It closes one Controller, loads its session and -sidecar into a second Boot, then observes structured readiness audits after an -external permission-only edit. Unchanged and content-edited files are controls. - -Boot 回归通过真实文件工具、验证命令及生产 Goal 持久化生成证明,关闭 Controller, -再用第二次 Boot 加载会话与 sidecar。外部只改权限后,测试检查结构化 readiness -审计,并保留未变更与内容变更对照。 - -Every arm still owes a high-risk review. The regression distinguishes which -verification, inspection and sign-off obligations return; it does not show an -otherwise complete Goal bypassing every finalization gate. - -所有分支仍欠高风险审查。回归区分恢复后哪些验证、检查和签收要求重新出现,不把 -这一局部证明错误描述为已经绕过所有完成门禁。 - -This is a scripted provider and two builds within one test process, not a -live incident, HTTP/browser test or actual process-death recovery. The Windows -inventory requires 14 named events across Agent and Boot without skips, -including parent events. Unix tests also refuse real links and a FIFO. - -The shared `scripts/windows-concurrency-tests.mjs` step reads the package-qualified -`carried-proof-file-state.json` inventory under `.github/windows-concurrency/`. -It retains all 14 requirements and both package terminals; broad smoke is separate. - -这是脚本 provider 与同一测试进程中的两次构建,不是线上事故、HTTP/浏览器测试 -或实际进程死亡恢复。Windows 清单要求 Agent 与 Boot 两个包的 14 个命名事件无 -skip 通过,计数包含父测试。Unix 测试另覆盖真实链接与 FIFO 的拒绝。 - -共享脚本读取 `.github/windows-concurrency/carried-proof-file-state.json` 中按包 -限定的清单,保留全部 14 项与两个包终态要求;broad smoke 仍单独运行。 - -For regular files on Windows this contract covers content and the read-only bit -only. Go's synthesized mode does not establish POSIX permission semantics or -cover Windows ACLs and full security descriptors. - -On any platform, Go file mode does not capture ownership or extended attributes. -The checks are observations, not an atomic -multi-file snapshot or protection against arbitrary concurrent external writers. -Rooted source authority, physical quiescence and durable publication remain separate. - -Windows 普通文件合同仅覆盖内容与只读位;Go 合成的模式不代表 POSIX 权限语义, -也不覆盖 Windows ACL 或完整安全描述符。任何平台上的 Go 模式均不涵盖所有者与 -扩展属性。这些检查是 -观察,不是多文件原子快照,也不能约束任意并发外部写入者。根目录授权、物理静默 -与持久发布仍由其他机制负责。 - -## Local cost observation / 本机开销观察 - -Three 200 ms benchmark samples on a Darwin/arm64 M1 Max produced these medians. -The old arm uses the exact preceding production owner with the same benchmark. -These are sequential local samples, not a production latency guarantee. - -| File size | Byte-only owner | File-state owner | Allocated bytes, old / new | -| --- | --- | --- | --- | -| 4 KiB | 18.569 µs/op | 28.771 µs/op | 5,400 / 34,552 | -| 1 MiB | 616.436 µs/op | 535.338 µs/op | 1,057,306 / 34,558 | - -Metadata checks add work for small files. The existing streaming content reader -uses bounded scratch space instead of allocating the whole regular file. -This does not establish a general speed-up or a bound for many-file recovery. - -上述结果来自 Darwin/arm64 M1 Max 上三次 200 ms 采样的中位数,旧侧使用精确前版 -生产 owner 与相同 benchmark。元数据检查增加小文件开销,流式读取减少大文件的 -整块分配;这些本机顺序采样不构成普遍加速结论或多文件恢复时延保证。 diff --git a/docs/SUBAGENT_COPY_ADMISSION.md b/docs/SUBAGENT_COPY_ADMISSION.md deleted file mode 100644 index 0bc134643a..0000000000 --- a/docs/SUBAGENT_COPY_ADMISSION.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -owner: @esengine -backup: @SivanCola -status: active -reviewed: 2026-10-28 ---- - -# Ancestor continuation admission / 祖先续跑准入 - -## Behavior / 行为 - -1. Within one `SubagentStore`, continuing an ancestor transcript reserves its - canonical nearest source and target parent session before searching for a - current-session copy. The reservation lasts until the returned run releases. -2. A competing continuation for that pair is refused as already in progress, - including before the first copy publishes its `running` metadata. It MUST - NOT create another copy or make another provider request. -3. `continue_from` and the accepted legacy `fork_from` input share this owner. - Referring to an older ancestor or its nearest lineage copy uses the same - reservation. Different target parents and different sources remain separate. -4. Failed preparation and abandoned unpublished runs release their reservation. - After a completed run releases, another continuation reuses its persisted - copy. Direct current-reference continuation keeps its existing ref lock. - -1. 同一 `SubagentStore` 在查找当前会话副本前,按最近祖先来源和目标父会话预留续跑归属;预留随返回的 run 一起释放。 -2. 首份副本尚未发布 `running` 元数据时,同一组合的竞争续跑也会被拒绝;不得再创建副本或发起模型请求。 -3. `continue_from` 与兼容的旧 `fork_from` 输入共用此归属。较早祖先及其最近副本归一到同一来源;不同目标会话、不同来源保持独立。 -4. 准备失败或放弃未发布的 run 会释放预留。已完成 run 释放后,续跑复用原持久化副本;直接按当前副本引用续跑仍使用原引用锁。 - -`errors.Is(err, ErrAncestorCopyBusy)` identifies the refusal through wrapping. -TaskTool uses the existing `subagent.settling` answer code and preserves that -sentinel; callers do not classify error prose. - -包装后的错误仍可用 `errors.Is(err, ErrAncestorCopyBusy)` 识别;TaskTool 使用既有 -`subagent.settling` 回答码并保留此标识,不解析错误文案。 - -## Compatibility and limits / 兼容与边界 - -| Boundary / 边界 | Contract / 合同 | -| --- | --- | -| Storage / 存储 | No metadata, transcript, status or schema change. / 不改变元数据、转录、状态或 schema。 | -| Existing ambiguity / 既有歧义 | Multiple existing copies remain refused; no automatic selection or deletion. / 已有多个副本仍拒绝,不自动选择或删除。 | -| Scope / 范围 | One Store instance; existing process-local locking contract. / 仅同一 Store 实例,沿用进程内锁合同。 | -| Cross-version writers / 跨版本写入 | No cross-process or old-writer fence; old binaries retain their behavior. / 不提供跨进程或旧写入者隔离。 | -| Recovery / 恢复 | No resume of failed/interrupted children, durable reservation or restart recovery. / 不恢复失败或中断子任务,不提供持久化预留与重启恢复。 | -| Authority / 权限 | Tool permission, cancellation authority, provider prefix and tool schema are unchanged. / 工具权限、取消权限、模型前缀和工具 schema 不变。 | - -## Validation / 验证 - -1. Store regressions hold an unpublished preparation, cover both input routes, - nearest-source aliases, independent parents/sources and release after errors. -2. TaskTool regressions block the existing parent-destruction callback before - `MarkRunning` writes metadata. A competing call is refused; the first call - receives the real persisted source transcript and creates the only copy. -3. These are local Store/TaskTool tests with a scripted provider, not a live - provider, full Boot, browser, crash/restart or physical-process-scope test. -4. The Windows workflow requires every named regression and the package terminal - pass, with no skips. Local cross-compilation is not native Windows evidence. - -1. Store 回归保留未发布的准备结果,覆盖两种输入、最近来源别名、不同会话和来源,以及错误后的释放。 -2. TaskTool 回归在 `MarkRunning` 写元数据前阻塞既有父会话销毁检查回调。竞争调用被拒绝,首个调用读取真实持久化来源转录并创建唯一副本。 -3. 以上是本机 Store/TaskTool 与脚本 provider 验证,不是线上 provider、完整 Boot、浏览器、崩溃重启或物理进程范围验证。 -4. Windows 工作流要求全部指定测试及包终态通过且零跳过;本机交叉编译不等于 Windows 原生执行。 - -A second TaskTool regression requests background execution without a job manager. -Preparation succeeds, then normal completion abandons the unstarted run. -No test calls `Release` for it; a foreground retry proves admission was freed. - -另一 TaskTool 回归在没有 job manager 时请求后台执行:准备成功后由正常结束路径 -放弃尚未启动的 run;测试不调用其 `Release`,前台重试证明预留已释放。 - -The shared `scripts/windows-concurrency-tests.mjs` step reads additive, -package-qualified inventories under `.github/windows-concurrency/`. This suite -requires 17 named passes including parents. The broad smoke remains. - -共享脚本读取 `.github/windows-concurrency/` 中按包限定的独立清单;此套件要求含 -父测试的 17 个指定测试通过,保留 broad smoke。 diff --git a/scripts/windows-concurrency-tests.mjs b/scripts/windows-concurrency-tests.mjs deleted file mode 100644 index 0c39d21277..0000000000 --- a/scripts/windows-concurrency-tests.mjs +++ /dev/null @@ -1,81 +0,0 @@ -// Focused Windows concurrency contracts live in additive, package-qualified -// inventories. New regressions do not need another workflow step or verifier. -import assert from 'node:assert/strict'; -import { closeSync, mkdirSync, openSync, readFileSync, readdirSync } from 'node:fs'; -import { dirname, join, resolve } from 'node:path'; -import { spawnSync } from 'node:child_process'; -import { fileURLToPath } from 'node:url'; - -export function readInventory(directory) { - const files = readdirSync(directory).filter(name => name.endsWith('.json')).sort(); - assert(files.length > 0, 'no Windows concurrency inventories'); - const required = new Map(); - for (const file of files) { - const groups = JSON.parse(readFileSync(join(directory, file), 'utf8')); - assert(Array.isArray(groups) && groups.length > 0, `${file}: empty inventory`); - for (const group of groups) { - assert(group && /^reasonix\/internal\/(?:[a-z0-9_]+\/)*[a-z0-9_]+$/.test(group.package), `${file}: invalid package`); - assert(Array.isArray(group.tests) && group.tests.length > 0, `${file}: empty tests`); - const tests = required.get(group.package) ?? new Set(); - for (const test of group.tests) { - assert(typeof test === 'string' && /^Test[A-Za-z0-9_]+(?:\/[^\s]+)?$/.test(test), `${file}: invalid test`); - tests.add(test); - } - required.set(group.package, tests); - } - } - for (const tests of required.values()) { - for (const test of tests) assert(tests.has(test.split('/')[0]), `missing parent for ${test}`); - } - return required; -} - -export function verifyInventory(required, raw) { - const passed = new Map(); - const packages = new Set(); - for (const line of raw.split(/\r?\n/).filter(line => line.trim())) { - const event = JSON.parse(line); - assert(required.has(event.Package), `unexpected package: ${event.Package}`); - assert(!['skip', 'fail'].includes(event.Action), `${event.Package}: ${event.Action}: ${event.Test ?? '(package)'}`); - if (event.Action !== 'pass') continue; - if (!event.Test) { - packages.add(event.Package); - continue; - } - const tests = passed.get(event.Package) ?? new Set(); - assert(!tests.has(event.Test), `duplicate pass: ${event.Package}/${event.Test}`); - tests.add(event.Test); - passed.set(event.Package, tests); - } - let count = 0; - for (const [pkg, tests] of required) { - assert(packages.has(pkg), `missing package terminal: ${pkg}`); - for (const test of tests) { - assert(passed.get(pkg)?.has(test), `missing test: ${pkg}/${test}`); - count++; - } - } - return { requiredTests: count, packages: required.size }; -} - -function main() { - const root = resolve(dirname(fileURLToPath(import.meta.url)), '..'); - const required = readInventory(join(root, '.github/windows-concurrency')); - const roots = [...new Set([...required.values()].flatMap(tests => [...tests].map(test => test.split('/')[0])))].sort(); - const output = resolve(process.argv[2] ?? join(process.env.RUNNER_TEMP ?? '.', 'concurrency-windows.jsonl')); - mkdirSync(dirname(output), { recursive: true }); - const fd = openSync(output, 'w'); - let result; - try { - result = spawnSync('go', ['test', '-count=1', '-timeout=3m', '-json', '-run', `^(${roots.join('|')})$`, ...required.keys()], { - cwd: root, stdio: ['ignore', fd, 'inherit'], - }); - } finally { - closeSync(fd); - } - assert(!result.error, result.error?.message); - assert.equal(result.status, 0, `go test failed (${result.signal ?? result.status}); see ${output}`); - console.log(JSON.stringify({ ...verifyInventory(required, readFileSync(output, 'utf8')), output })); -} - -if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) main(); diff --git a/scripts/windows-concurrency-tests.test.mjs b/scripts/windows-concurrency-tests.test.mjs deleted file mode 100644 index fab3f327db..0000000000 --- a/scripts/windows-concurrency-tests.test.mjs +++ /dev/null @@ -1,64 +0,0 @@ -import assert from 'node:assert/strict'; -import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; -import { tmpdir } from 'node:os'; -import { join } from 'node:path'; -import { spawnSync } from 'node:child_process'; -import test from 'node:test'; -import { readInventory, verifyInventory } from './windows-concurrency-tests.mjs'; - -test('long invalid subtest suffix is rejected without repeated slash partitioning', () => { - const dir = mkdtempSync(join(tmpdir(), 'concurrency-inventory-')); - try { - const inventory = tests => JSON.stringify([{ package: 'reasonix/internal/example', tests }]); - const file = join(dir, 'names.json'); - const valid = ['Test0', 'Test0/a/b', 'Test0/!/', 'Test0//']; - writeFileSync(file, inventory(valid)); - assert.deepEqual([...readInventory(dir).values()][0], new Set(valid)); - writeFileSync(file, inventory(['Test0', `Test0/${'!/'.repeat(10000)} `])); - const script = `import assert from 'node:assert/strict'; - import { readInventory } from ${JSON.stringify(new URL('./windows-concurrency-tests.mjs', import.meta.url).href)}; - assert.throws(() => readInventory(process.argv[1]), /invalid test/);`; - const result = spawnSync(process.execPath, ['--input-type=module', '-e', script, dir], { timeout: 5000, encoding: 'utf8' }); - assert.ifError(result.error); - assert.equal(result.status, 0, result.stderr); - } finally { - rmSync(dir, { recursive: true, force: true }); - } -}); - -test('additive manifests keep package-qualified requirements', () => { - const dir = mkdtempSync(join(tmpdir(), 'concurrency-inventory-')); - try { - const a = 'reasonix/internal/first', b = 'reasonix/internal/second'; - writeFileSync(join(dir, 'one.json'), JSON.stringify([{ package: a, tests: ['TestShared', 'TestShared/case'] }])); - writeFileSync(join(dir, 'two.json'), JSON.stringify([{ package: b, tests: ['TestShared'] }])); - const required = readInventory(dir); - const events = [ - { Package: a, Action: 'pass', Test: 'TestShared/case' }, - { Package: a, Action: 'pass', Test: 'TestShared' }, - { Package: a, Action: 'pass' }, - { Package: b, Action: 'pass', Test: 'TestShared' }, - { Package: b, Action: 'pass' }, - ]; - const raw = values => values.map(value => JSON.stringify(value)).join('\r\n'); - assert.deepEqual(verifyInventory(required, raw(events)), { requiredTests: 3, packages: 2 }); - for (let i = 0; i < events.length; i++) { - assert.throws(() => verifyInventory(required, raw(events.filter((_, index) => index !== i)))); - assert.throws(() => verifyInventory(required, raw(events.map((event, index) => index === i ? { ...event, Action: 'skip' } : event)))); - } - assert.throws(() => verifyInventory(required, raw([...events, { Package: a, Action: 'fail' }]))); - assert.throws(() => verifyInventory(required, raw([...events, events[0]]))); - assert.throws(() => verifyInventory(required, '{')); - writeFileSync(join(dir, 'two.json'), JSON.stringify([{ package: b, tests: ['TestOrphan/case'] }])); - assert.throws(() => readInventory(dir)); - writeFileSync(join(dir, 'two.json'), JSON.stringify([{ package: '../other', tests: ['TestShared'] }])); - assert.throws(() => readInventory(dir)); - writeFileSync(join(dir, 'two.json'), '[]'); - assert.throws(() => readInventory(dir)); - rmSync(join(dir, 'one.json')); - rmSync(join(dir, 'two.json')); - assert.throws(() => readInventory(dir)); - } finally { - rmSync(dir, { recursive: true, force: true }); - } -});