diff --git a/.github/workflows/project-native-research.yml b/.github/workflows/project-native-research.yml new file mode 100644 index 000000000..d1b8b9151 --- /dev/null +++ b/.github/workflows/project-native-research.yml @@ -0,0 +1,98 @@ +name: Remaining Project Native Research +on: + pull_request: + paths: + - '.github/workflows/project-native-research.yml' + - 'scripts/project_native_research.py' + - 'scripts/project_native_cursor_acquisition.py' + - 'scripts/project_native_service.py' + - 'scripts/project_native_collectors/**' + - 'scripts/test_project_native_*.py' + - 'scripts/native_client_research.py' + - 'scripts/native_client_project_artifacts.py' + - 'scripts/research-grok-native.py' + - 'scripts/run-native-client-matrix.py' + - 'repotests/testdata/agentplugins_native_probe/**' + workflow_dispatch: +permissions: + contents: read +concurrency: + group: project-native-research-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} +jobs: + contracts: + name: Inert contracts and explicit research selection + runs-on: ubuntu-24.04 + timeout-minutes: 5 + outputs: + matrix: ${{ steps.selection.outputs.matrix }} + count: ${{ steps.selection.outputs.count }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - name: Test capture, pins, admission and leaf parsers without vendor execution + run: python3 -m unittest discover -s scripts -p 'test_project_native_*.py' + - name: Select only declared research phases + id: selection + run: | + python3 - <<'PYTHON' + import json, os, subprocess + result = subprocess.check_output(['python3', 'scripts/project_native_research.py', '--matrix'], text=True).strip() + matrix = json.loads(result) + with open(os.environ['GITHUB_OUTPUT'], 'a') as output: + output.write('matrix=' + result + '\n') + output.write('count=' + str(len(matrix['include'])) + '\n') + print(result) + print('Research selection does not qualify lifecycle, MCP, model use or a release.') + PYTHON + research: + name: ${{ matrix.client }} / ${{ matrix.phase }} / current source + needs: contracts + if: ${{ needs.contracts.outputs.count != '0' }} + strategy: + fail-fast: false + max-parallel: 5 + matrix: ${{ fromJSON(needs.contracts.outputs.matrix) }} + runs-on: ${{ matrix.host }} + timeout-minutes: 10 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + if: ${{ matrix.client == 'kimi' && matrix.phase == 'observe' }} + with: + go-version: '1.26.10' + cache: false + - name: Acquire or observe exact native bytes in a fresh original profile + env: + AGENTPLUGINS_NATIVE_DISPOSABLE_HOSTED: '1' + EXPECTED_COMMIT: ${{ github.event.pull_request.head.sha || github.sha }} + run: python3 scripts/project_native_research.py --client '${{ matrix.client }}' --phase '${{ matrix.phase }}' --output '${{ runner.temp }}/project-native-${{ matrix.client }}' + - name: Admit the exact bounded evidence ZIP + id: admission + if: ${{ always() }} + env: + EVIDENCE: ${{ runner.temp }}/project-native-${{ matrix.client }}/upload/research.zip + run: | + /usr/bin/python3 -I - <<'PYTHON' + import os, stat + from pathlib import Path + path = Path(os.environ['EVIDENCE']) + info = path.lstat() + if path.resolve() != path or not stat.S_ISREG(info.st_mode) or info.st_nlink != 1 or info.st_uid != os.getuid() or info.st_size > 32 * 1024 * 1024: + raise SystemExit('refusing nonregular or unbounded research ZIP') + with open(os.environ['GITHUB_OUTPUT'], 'a') as output: + output.write('valid=true\n') + PYTHON + - name: Upload closed research evidence + if: ${{ always() && steps.admission.outputs.valid == 'true' }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0 + with: + name: project-native-${{ matrix.client }}-${{ matrix.phase }}-linux-amd64 + path: ${{ runner.temp }}/project-native-${{ matrix.client }}/upload/research.zip + if-no-files-found: error + retention-days: 14 diff --git a/.github/workflows/project-native-runtime.yml b/.github/workflows/project-native-runtime.yml new file mode 100644 index 000000000..b079de211 --- /dev/null +++ b/.github/workflows/project-native-runtime.yml @@ -0,0 +1,134 @@ +name: Project Native Runtime +on: + pull_request: + paths: + - '.github/workflows/project-native-runtime.yml' + - 'scripts/project_native_runtime.py' + - 'scripts/project_native_research.py' + - 'scripts/project_native_service.py' + - 'scripts/project_native_collectors/**' + - 'scripts/test_project_native_runtime.py' + - 'repotests/agentplugins_*project_native_*test.go' + - 'repotests/testdata/agentplugins_native_probe/**' + workflow_dispatch: +permissions: + contents: read +concurrency: + group: project-native-runtime-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} +jobs: + contracts: + name: Runtime admission contracts and exact selection + runs-on: ubuntu-24.04 + timeout-minutes: 5 + outputs: + matrix: ${{ steps.selection.outputs.matrix }} + count: ${{ steps.selection.outputs.count }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - name: Verify inert envelope and selection contracts + run: python3 -m unittest discover -s scripts -p 'test_project_native_runtime.py' + - name: Select only implemented exact native tests + id: selection + run: | + python3 - <<'PYTHON' + import json, os, subprocess + value = subprocess.check_output(['python3', 'scripts/project_native_runtime.py', '--matrix'], text=True).strip() + matrix = json.loads(value) + with open(os.environ['GITHUB_OUTPUT'], 'a') as output: + output.write('matrix=' + value + '\n') + output.write('count=' + str(len(matrix['include'])) + '\n') + print(value) + PYTHON + - name: Prepare pinned Go for selected Copilot inert process contracts + if: ${{ contains(fromJSON(steps.selection.outputs.matrix).include.*.client, 'copilot') }} + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + with: + go-version: '1.26.10' + cache: false + - name: Verify selected Copilot inert process contracts before native execution + if: ${{ contains(fromJSON(steps.selection.outputs.matrix).include.*.client, 'copilot') }} + run: go test -json -p=1 -count=1 -timeout=120s ./repotests -run '^(TestCopilot|TestProjectNativeRuntime)' + native: + name: ${{ matrix.client }} / ${{ matrix.phase }} / installed public CLI + needs: contracts + if: ${{ needs.contracts.outputs.count != '0' }} + strategy: + fail-fast: false + max-parallel: 3 + matrix: ${{ fromJSON(needs.contracts.outputs.matrix) }} + runs-on: ubuntu-24.04 + timeout-minutes: 26 + env: + AGENTPLUGINS_NATIVE_DISPOSABLE_HOSTED: '1' + EXPECTED_COMMIT: ${{ github.event.pull_request.head.sha || github.sha }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - name: Admit actual hosted environment and clean source before toolchain setup + run: | + python3 - <<'PYTHON' + import os, platform, re, sys + from pathlib import Path + sys.path.insert(0, str(Path.cwd() / 'scripts')) + from native_client_research import run_probe + required = {'GITHUB_ACTIONS': 'true', 'RUNNER_ENVIRONMENT': 'github-hosted', 'AGENTPLUGINS_NATIVE_DISPOSABLE_HOSTED': '1'} + if any(os.environ.get(key) != value for key, value in required.items()) or platform.system() != 'Linux' or platform.machine() != 'x86_64': + raise SystemExit('actual opted-in GitHub-hosted Linux x64 required') + expected = os.environ['EXPECTED_COMMIT'] + env = {'PATH': '/usr/bin:/bin', 'LC_ALL': 'C', 'GIT_CONFIG_NOSYSTEM': '1', 'GIT_CONFIG_GLOBAL': '/dev/null', 'GIT_TERMINAL_PROMPT': '0'} + def git(*args): + record, stdout, stderr = run_probe(['/usr/bin/git', *args], Path.cwd(), env, Path('/tmp'), 'source-guard', timeout=10, limit=65536, memory_only=True) + if record['error'] is not None or record['exit'] != 0 or stderr: + raise SystemExit('bounded source identity query failed') + return stdout.decode('ascii', errors='strict').strip() + if not re.fullmatch('[0-9a-f]{40}', expected) or git('rev-parse', 'HEAD') != expected or not re.fullmatch('[0-9a-f]{40}', git('rev-parse', 'HEAD^{tree}')) or git('status', '--porcelain', '--untracked-files=normal'): + raise SystemExit('exact clean current-source checkout required') + PYTHON + - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + with: + go-version: '1.26.10' + cache: false + - name: Run the selected bounded current-source native test + run: python3 scripts/project_native_runtime.py --client '${{ matrix.client }}' --output '${{ runner.temp }}/project-runtime-${{ matrix.client }}' + - name: Admit exact closed output files + id: admission + if: ${{ always() }} + env: + EVIDENCE: ${{ runner.temp }}/project-runtime-${{ matrix.client }}/upload + run: | + /usr/bin/python3 -I - <<'PYTHON' + import os, stat + from pathlib import Path + root = Path(os.environ['EVIDENCE']) + for label in ('frontend', 'runtime'): + path = root / (label + '.zip') + if not path.exists(): + continue + info = path.lstat() + if path.resolve() != path or not stat.S_ISREG(info.st_mode) or info.st_nlink != 1 or info.st_uid != os.getuid() or info.st_size > 32 * 1024 * 1024: + raise SystemExit('refusing aliased or unbounded closed evidence') + with open(os.environ['GITHUB_OUTPUT'], 'a') as output: + output.write(label + '=true\n') + PYTHON + - name: Upload source, build and test receipt + if: ${{ always() && steps.admission.outputs.frontend == 'true' }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0 + with: + name: project-runtime-${{ matrix.client }}-${{ matrix.phase }}-frontend + path: ${{ runner.temp }}/project-runtime-${{ matrix.client }}/upload/frontend.zip + if-no-files-found: error + retention-days: 14 + - name: Upload admitted native runtime evidence + if: ${{ always() && steps.admission.outputs.runtime == 'true' }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0 + with: + name: project-runtime-${{ matrix.client }}-${{ matrix.phase }}-native + path: ${{ runner.temp }}/project-runtime-${{ matrix.client }}/upload/runtime.zip + if-no-files-found: error + retention-days: 14 diff --git a/cli/cmd/agentplugins/cursor_project_cycle_contract_test.go b/cli/cmd/agentplugins/cursor_project_cycle_contract_test.go new file mode 100644 index 000000000..7bf19ae24 --- /dev/null +++ b/cli/cmd/agentplugins/cursor_project_cycle_contract_test.go @@ -0,0 +1,110 @@ +package main + +import ( + "bytes" + "encoding/json" + "os" + "path/filepath" + "reflect" + "strings" + "testing" + + "github.com/777genius/plugin-kit-ai/cli/internal/agentpluginscli" +) + +// Real public Cobra/installer/filesystem composition with inert host discovery +// and assessment. No Cursor process or authored MCP process is executed. +func TestProjectCursorDirectMCPCyclePublicContracts(t *testing.T) { + f := newCursorProjectJourney(t, newProjectJourneyTransport(t, "zip")) + projectJourneyWrite(t, filepath.Join(f.a, ".cursor", "mcp.json"), "{\"mcpServers\":{}}\n") + source := projectJourneyTemp(t) + write := func(version string) { + t.Helper() + projectJourneyWrite(t, filepath.Join(source, "plugin.json"), `{"$schema":"https://agent-plugins.org/schemas/1.0.0/plugin.schema.json","name":"native-proof","version":"`+version+`"}`+"\n") + projectJourneyWrite(t, filepath.Join(source, "mcp.json"), `{"$schema":"https://agent-plugins.org/schemas/1.0.0/mcp.schema.json","mcpServers":{"uapcursora":{"type":"stdio","command":"./bin/probe","args":["cursor-component"],"cwd":"${PLUGIN_ROOT}"}}}`+"\n") + projectJourneyWrite(t, filepath.Join(source, "bin", "probe"), "inert fixture bytes; never executed\n") + if err := os.Chmod(filepath.Join(source, "bin", "probe"), 0700); err != nil { + t.Fatal(err) + } + } + write("1.0.0") + var iid, oldState string + run := func(stage, verb, selector string, changed bool) { + t.Helper() + var stdout, stderr bytes.Buffer + app := f.app + app.Input, app.Output, app.ErrorOutput, app.Terminal = strings.NewReader(""), &stdout, &stderr, false + root := agentpluginscli.NewRoot(app) + args := []string{verb, selector, "--scope", "project", "--project-root", f.a, "--target", "cursor", "--format", "json"} + if verb == "add" { + args = append(args, "--no-save") + } + root.SetArgs(args) + if err := root.Execute(); err != nil { + t.Fatalf("%s: %v\n%s\n%s", stage, err, stdout.String(), stderr.String()) + } + var row map[string]any + if err := json.Unmarshal(stdout.Bytes(), &row); err != nil { + t.Fatal(err) + } + data := row["data"].(map[string]any) + output := data + if stage == "repeat-add-a" { + if _, present := data["targets"]; present || data["operation_id"] != nil { + t.Fatal("repeat add is not the exact singleton") + } + } else { + if data["batch"] != true || data["succeeded"] != float64(1) || data["failed"] != float64(0) { + t.Fatal("public batch differs", row) + } + output = data["targets"].([]any)[0].(map[string]any)["output"].(map[string]any) + } + outcome := output["result"].(map[string]any) + if iid == "" { + iid = outcome["installation_id"].(string) + } + if outcome["installation_id"] != iid || outcome["mutated"] != changed || outcome["requires_confirmation"] != false { + t.Fatal("held public outcome differs", row) + } + label := "direct local source" + if verb == "repair" || verb == "remove" { + label = "local" + } + if output["source"] != label { + t.Fatal("source label differs", row) + } + if verb != "remove" { + plan, activation := outcome["plan"].(map[string]any), outcome["activation"].(map[string]any) + if plan["verification"] != "package_validated" || activation["verification"] != "installation_verified" || !reflect.DeepEqual(plan["components"], []any{map[string]any{"kind": "mcp_server", "name": "uapcursora", "support": "native"}}) { + t.Fatal("Prepared MCP-only DTO differs", row) + } + } + if stage == "unchanged-update-a" && outcome["no_change"] != true { + t.Fatal("unchanged update flag differs", row) + } + state := projectJourneyRead(t, filepath.Join(f.a, ".uap", "state-v2.json")) + if !changed && state != oldState { + t.Fatal("public no-op rewrote exact state") + } + oldState = state + } + run("add-a", "add", source, true) + run("repeat-add-a", "add", source, false) + run("unchanged-update-a", "update", iid, false) + run("intact-repair-a", "repair", iid, true) + write("1.1.0") + run("update-a", "update", iid, true) + // Remove only the sole owned native document, leaving the package intact. + config := filepath.Join(f.a, ".cursor", "mcp.json") + if err := os.Remove(config); err != nil { + t.Fatal(err) + } + run("missing-repair-a", "repair", iid, true) + run("remove-a", "remove", iid, true) + if _, err := f.execute(f.a, "remove", iid, "--target", "cursor"); err == nil || err.Error() != `plugin is not installed for target "cursor" in project scope; no target was changed` { + t.Fatal("repeated removal refusal differs", err) + } + if projectJourneyRead(t, filepath.Join(f.a, ".uap", "state-v2.json")) != oldState { + t.Fatal("repeated removal changed state") + } +} diff --git a/cli/cmd/agentplugins/cursor_writer_public_contract_test.go b/cli/cmd/agentplugins/cursor_writer_public_contract_test.go new file mode 100644 index 000000000..06f7954b9 --- /dev/null +++ b/cli/cmd/agentplugins/cursor_writer_public_contract_test.go @@ -0,0 +1,179 @@ +package main + +import ( + "bytes" + "encoding/json" + "os" + "path/filepath" + "reflect" + "strings" + "testing" + + "github.com/777genius/plugin-kit-ai/cli/internal/agentpluginscli" +) + +// Exercise the same native writer and no-change lifecycle with a tiny remote +// recipe. No endpoint is contacted and no managed stdio launcher is copied. +func TestProjectCursorNativeWriterLockPublicContracts(t *testing.T) { + f := newCursorProjectJourney(t, newProjectJourneyTransport(t, "zip")) + profile := filepath.Join(f.a, ".cursor") + // These are this fixture's known leaves, removed before the new baseline. + for _, name := range []string{"hooks.json", "skills/foreign/SKILL.md", "skills/foreign", "skills", "mcp.json"} { + if err := os.Remove(filepath.Join(profile, filepath.FromSlash(name))); err != nil { + t.Fatal(err) + } + } + projectJourneyWrite(t, filepath.Join(profile, "foreign-owned.txt"), "caller-owned a\n") + var writerLock os.FileInfo + source := projectJourneyTemp(t) + write := func(version string) { + t.Helper() + projectJourneyWrite(t, filepath.Join(source, "plugin.json"), `{"$schema":"https://agent-plugins.org/schemas/1.0.0/plugin.schema.json","name":"native-proof","version":"`+version+`"}`+"\n") + projectJourneyWrite(t, filepath.Join(source, "mcp.json"), `{"$schema":"https://agent-plugins.org/schemas/1.0.0/mcp.schema.json","mcpServers":{"uapcursora":{"type":"streamable-http","url":"http://127.0.0.1:9/mcp"}}}`+"\n") + } + write("1.0.0") + var iid, oldState string + run := func(stage, verb, selector string, changed bool) { + t.Helper() + var stdout, stderr bytes.Buffer + app := f.app + app.Input, app.Output, app.ErrorOutput, app.Terminal = strings.NewReader(""), &stdout, &stderr, false + root := agentpluginscli.NewRoot(app) + args := []string{verb, selector, "--scope", "project", "--project-root", f.a, "--target", "cursor", "--format", "json"} + if verb == "add" { + args = append(args, "--no-save") + } + root.SetArgs(args) + if err := root.Execute(); err != nil { + t.Fatalf("%s: %v\n%s\n%s", stage, err, stdout.String(), stderr.String()) + } + var row map[string]any + if err := json.Unmarshal(stdout.Bytes(), &row); err != nil { + t.Fatal(err) + } + data := row["data"].(map[string]any) + output := data + if stage == "repeat-add-a" { + if _, present := data["targets"]; present || data["operation_id"] != nil { + t.Fatal("repeat add is not the exact singleton") + } + } else { + if data["batch"] != true || data["succeeded"] != float64(1) || data["failed"] != float64(0) { + t.Fatal("public batch differs", row) + } + output = data["targets"].([]any)[0].(map[string]any)["output"].(map[string]any) + } + outcome := output["result"].(map[string]any) + keys := map[string]bool{"installation_id": true, "requires_confirmation": true, "mutated": true} + if verb == "remove" { + for _, key := range []string{"plugin", "client_id", "affected_surfaces", "deactivation", "group_phase"} { + keys[key] = true + } + } else { + keys["plan"], keys["activation"] = true, true + if stage != "repeat-add-a" { + keys["group_phase"] = true + } + if stage == "repeat-add-a" || stage == "unchanged-update-a" { + keys["no_change"] = true + if outcome["no_change"] != true { + t.Fatal("observed read-only result lost no_change", stage) + } + } + } + if len(outcome) != len(keys) { + t.Fatal("exact measured public result keys differ", stage, outcome) + } + for key := range outcome { + if !keys[key] { + t.Fatal("unknown public result key", stage, key) + } + } + if stage != "repeat-add-a" && outcome["group_phase"] != "external_completed" { + t.Fatal("measured public group phase differs", stage) + } + if iid == "" { + iid = outcome["installation_id"].(string) + } + if outcome["installation_id"] != iid || outcome["mutated"] != changed || outcome["requires_confirmation"] != false { + t.Fatal("held public outcome differs", row) + } + label := "direct local source" + if verb == "repair" || verb == "remove" { + label = "local" + } + if output["source"] != label { + t.Fatal("source label differs", row) + } + if verb != "remove" { + plan, activation := outcome["plan"].(map[string]any), outcome["activation"].(map[string]any) + if plan["verification"] != "package_validated" || activation["verification"] != "installation_verified" || !reflect.DeepEqual(plan["components"], []any{map[string]any{"kind": "mcp_server", "name": "uapcursora", "support": "native"}}) { + t.Fatal("Prepared MCP-only DTO differs", row) + } + } + if stage == "unchanged-update-a" && outcome["no_change"] != true { + t.Fatal("unchanged update flag differs", row) + } + state := projectJourneyRead(t, filepath.Join(f.a, ".uap", "state-v2.json")) + if !changed && state != oldState { + t.Fatal("public no-op rewrote exact state") + } + oldState = state + writerLock = cursorNativeWriterProfileContract(t, profile, true, writerLock) + } + run("add-a", "add", source, true) + run("repeat-add-a", "add", source, false) + run("unchanged-update-a", "update", iid, false) + run("intact-repair-a", "repair", iid, true) + write("1.1.0") + run("update-a", "update", iid, true) + // Remove only the sole owned native document, leaving the package intact. + config := filepath.Join(f.a, ".cursor", "mcp.json") + if err := os.Remove(config); err != nil { + t.Fatal(err) + } + writerLock = cursorNativeWriterProfileContract(t, profile, false, writerLock) + run("missing-repair-a", "repair", iid, true) + run("remove-a", "remove", iid, true) + if _, err := f.execute(f.a, "remove", iid, "--target", "cursor"); err == nil || err.Error() != `plugin is not installed for target "cursor" in project scope; no target was changed` { + t.Fatal("repeated removal refusal differs", err) + } + if projectJourneyRead(t, filepath.Join(f.a, ".uap", "state-v2.json")) != oldState { + t.Fatal("repeated removal changed state") + } + cursorNativeWriterProfileContract(t, profile, true, writerLock) +} + +func cursorNativeWriterProfileContract(t *testing.T, root string, configured bool, held os.FileInfo) os.FileInfo { + t.Helper() + want := map[string]bool{"foreign-owned.txt": true, "mcp.json.agentplugins.lock": true} + if configured { + want["mcp.json"] = true + } + entries, err := os.ReadDir(root) + if err != nil || len(entries) != len(want) { + t.Fatalf("exact public Cursor profile membership: %v, %v", entries, err) + } + for _, entry := range entries { + if !want[entry.Name()] || !entry.Type().IsRegular() { + t.Fatal("unknown or non-ordinary public profile member", entry.Name()) + } + } + path := filepath.Join(root, "mcp.json.agentplugins.lock") + info, err := os.Lstat(path) + if err != nil || !info.Mode().IsRegular() || info.Size() != 0 { + t.Fatal("source-defined empty writer lock differs", err) + } + if body, err := os.ReadFile(path); err != nil || len(body) != 0 { + t.Fatal("writer lock body differs", err) + } + // The Linux-tagged frame contract checks exact 0600 and numeric ownership. + // This portable route also preserves the actual lock identity and mode. + if held != nil && (!os.SameFile(held, info) || held.Mode() != info.Mode()) { + t.Fatal("public lifecycle replaced writer lock authority") + } + if projectJourneyRead(t, filepath.Join(root, "foreign-owned.txt")) != "caller-owned a\n" { + t.Fatal("public lifecycle changed the foreign caller file") + } + return info +} diff --git a/cli/cmd/agentplugins/devin_project_cache_measurement_linux_test.go b/cli/cmd/agentplugins/devin_project_cache_measurement_linux_test.go new file mode 100644 index 000000000..dbd4aa249 --- /dev/null +++ b/cli/cmd/agentplugins/devin_project_cache_measurement_linux_test.go @@ -0,0 +1,284 @@ +//go:build linux + +package main + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "io" + "os" + "path/filepath" + "reflect" + "sort" + "syscall" + "testing" + "time" + + "github.com/777genius/plugin-kit-ai/cli/internal/agentpluginscli" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/adapters/securityscan" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/adapters/specregistry" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/domain" +) + +type windDirectCacheFact struct { + Device, Inode, Links uint64 + UID, GID, Mode uint32 + Size int64 + Modified, Changed syscall.Timespec + Digest string +} + +type windDirectCacheProbe struct { + root string + scanner *windUserCacheScanner + before map[string]windDirectCacheFact + keys map[string]bool + stage int + start, end time.Time +} + +func windDirectCacheSHA(body []byte) string { + digest := sha256.Sum256(body) + return hex.EncodeToString(digest[:]) +} + +func newWindDirectCacheJourney(t *testing.T) (devinProjectJourney, *windDirectCacheProbe) { + t.Helper() + f := devinProjectJourney{projectJourney{home: devinJourneyTemp(t), a: devinJourneyTemp(t), b: devinJourneyTemp(t)}} + f.cache = filepath.Join(f.home, "uap") + for _, root := range []string{"", f.a, f.b} { + native := f.devinRoot(root) + projectJourneyWrite(t, filepath.Join(native, "mcp_config.json"), `{"mcpServers":{"foreign":{"url":"https://foreign.test/mcp","disabled":true}},"foreignPreference":"keep"}`) + projectJourneyWrite(t, filepath.Join(native, "skills", "foreign", "SKILL.md"), "foreign skill\n") + projectJourneyWrite(t, filepath.Join(native, "hooks.json"), "foreign hooks\n") + } + scratch := devinJourneyTemp(t) + for _, name := range []string{"TMPDIR", "TEMP", "TMP"} { + t.Setenv(name, scratch) + } + registry, err := specregistry.New() + if err != nil { + t.Fatal(err) + } + app, err := newAgentpluginsCLIApp(f.home, f.cache, nil, nil, nil, registry) + if err != nil { + t.Fatal(err) + } + scanner := &windUserCacheScanner{} + f.app = windDirectCacheApp(t, app, f.home, scanner) + if err := os.MkdirAll(filepath.Join(f.cache, "security", "assessments"), 0700); err != nil { + t.Fatal(err) + } + projectJourneyWrite(t, filepath.Join(f.cache, "security", "lintai", "caller-owned.txt"), "original scanner cache marker; never executed\n") + probe := &windDirectCacheProbe{root: f.cache, scanner: scanner, keys: map[string]bool{}} + probe.before = windDirectCacheFrame(t, f.cache) + return f, probe +} + +func windDirectCacheApp(t *testing.T, app agentpluginscli.App, home string, scanner *windUserCacheScanner) agentpluginscli.App { + t.Helper() + app.Detector = devinProjectDetector{root: filepath.Join(home, ".devin")} + app.SecurityIndex, app.DirectoryClient, app.DiscoveryClient = nil, nil, nil + app.DirectoryClientForDryRun, app.CommitDirectoryPreview = nil, nil + evaluator, ok := app.SecurityEvaluator.(securityscan.Evaluator) + if !ok { + t.Fatal("default evaluator absent") + } + cache, ok := evaluator.Cache.(securityscan.FileCache) + if !ok || cache.Root != filepath.Join(home, "uap", "security", "assessments") || evaluator.Requirement != securityscan.DefaultRequirement() { + t.Fatal("default file cache absent") + } + acquirer, ok := app.SourceAcquirer.(lazySourceAcquirer) + if !ok || acquirer.dataRoot != filepath.Join(home, "uap") || acquirer.acquirer.TempRoot != acquirer.dataRoot { + t.Fatal("default lazy acquirer absent") + } + evaluator.Scanner = scanner + app.SecurityEvaluator = evaluator + compose := app.ForScope + app.ForScope = func(scope domain.InstallScope, root string) (agentpluginscli.App, error) { + selected, err := compose(scope, root) + if err != nil { + return selected, err + } + return windDirectCacheApp(t, selected, home, scanner), nil + } + return app +} + +func windDirectCacheInfo(t *testing.T, info os.FileInfo) windDirectCacheFact { + t.Helper() + s, ok := info.Sys().(*syscall.Stat_t) + if !ok || s.Uid != uint32(os.Getuid()) || s.Gid != uint32(os.Getgid()) || s.Ino == 0 || (!info.IsDir() && (!info.Mode().IsRegular() || s.Nlink != 1)) { + t.Fatal("ordinary owned cache authority required") + } + return windDirectCacheFact{Device: s.Dev, Inode: s.Ino, Links: s.Nlink, UID: s.Uid, GID: s.Gid, Mode: s.Mode, Size: s.Size, Modified: s.Mtim, Changed: s.Ctim} +} + +func windDirectCacheFrame(t *testing.T, root string) map[string]windDirectCacheFact { + t.Helper() + frame := map[string]windDirectCacheFact{} + err := filepath.WalkDir(root, func(path string, entry os.DirEntry, err error) error { + if err != nil { + return err + } + name, err := filepath.Rel(root, path) + if err != nil { + return err + } + info, err := os.Lstat(path) + if err != nil { + return err + } + fact := windDirectCacheInfo(t, info) + if !entry.IsDir() { + fd, err := syscall.Open(path, syscall.O_RDONLY|syscall.O_NOFOLLOW|syscall.O_NONBLOCK, 0) + if err != nil { + return err + } + file := os.NewFile(uintptr(fd), path) + body, readErr := io.ReadAll(io.LimitReader(file, (1<<20)+1)) + after, statErr := file.Stat() + closeErr := file.Close() + if readErr != nil || statErr != nil || closeErr != nil || len(body) > 1<<20 || !os.SameFile(info, after) || fact != windDirectCacheInfo(t, after) { + t.Fatal("cache read frame changed") + } + fact.Digest = windDirectCacheSHA(body) + } + frame[filepath.ToSlash(name)] = fact + if len(frame) > 32 { + t.Fatal("finite cache inventory exceeded") + } + return nil + }) + if err != nil { + t.Fatal(err) + } + return frame +} + +func (probe *windDirectCacheProbe) observe(t *testing.T, stage string, raw []byte, installation domain.Installation) { + t.Helper() + stages := []string{"add-a", "add-b", "repeat-add-a", "unchanged-update-a", "intact-repair-a", "update-a", "missing-repair-a", "remove-a", "repeat-remove-a", "remove-b"} + scans := []int{1, 2, 2, 2, 2, 3, 3, 3, 3, 3} + if probe.stage >= len(stages) || stages[probe.stage] != stage || probe.scanner.calls != scans[probe.stage] { + t.Fatalf("measured scan ledger differs: stage=%s index=%d calls=%d", stage, probe.stage, probe.scanner.calls) + } + requirement := securityscan.DefaultRequirement() + subject := domain.SecuritySubject{TreeDigest: installation.Source.TreeDigest, ManifestDigest: installation.Package.ManifestDigest} + key := securityscan.CacheKey(subject, requirement) + _, existed := probe.keys[key] + probe.keys[key] = true + after := windDirectCacheFrame(t, probe.root) + for name, fact := range after { + old, present := probe.before[name] + if present && old == fact { + continue + } + if name == "." || name == "security/assessments" && !existed { + left, right := old, fact + left.Modified, left.Changed, right.Modified, right.Changed = syscall.Timespec{}, syscall.Timespec{}, syscall.Timespec{}, syscall.Timespec{} + if name == "security/assessments" { + left.Size, right.Size = 0, 0 + } + if !present || left != right || fact.Size < 0 || fact.Size > 1<<20 { + t.Fatal("cache parent changed unrelated authority", name) + } + for _, stamp := range []syscall.Timespec{fact.Modified, fact.Changed} { + when := time.Unix(stamp.Sec, stamp.Nsec) + if stamp.Nsec < 0 || stamp.Nsec >= 1e9 || when.Before(probe.start) || when.After(probe.end) { + t.Fatal("cache parent timestamp outside actual command") + } + } + continue + } + if !present && !existed && name == "security/assessments/"+key+".json" { + continue + } + t.Fatal("cache lifecycle changed unrelated original record", name) + } + for name := range probe.before { + if _, ok := after[name]; !ok { + t.Fatal("cache lifecycle removed prior record", name) + } + } + entries, err := os.ReadDir(filepath.Join(probe.root, "security", "assessments")) + if err != nil || len(entries) != len(probe.keys) { + t.Fatal("finite assessment membership differs", err) + } + for _, entry := range entries { + name := entry.Name() + if len(name) != 69 || filepath.Ext(name) != ".json" || !probe.keys[name[:64]] { + t.Fatal("unexpected cache key") + } + } + cache := securityscan.FileCache{Root: filepath.Join(probe.root, "security", "assessments")} + assessment, found := cache.Load(key) + want := domain.SecurityAssessment{SchemaVersion: 1, Subject: subject, Scanner: requirement.Scanner, Policy: requirement.Policy, Outcome: domain.SecurityNoBlockingFindings, ScannedFiles: 3, ReportDigest: "sha256:" + windDirectCacheSHA([]byte(windUserCacheReport))} + if !found || assessment.Validate(requirement, subject) != nil || !reflect.DeepEqual(assessment, want) { + t.Fatal("exact cache subject/policy/report differs") + } + expected, err := json.Marshal(assessment) + path := filepath.Join(cache.Root, key+".json") + file := after["security/assessments/"+key+".json"] + sameBytes := projectJourneyRead(t, path) == string(expected) + sameMode := file.Mode == 0100600 + sameSize := file.Size == int64(len(expected)) + sameDigest := file.Digest == windDirectCacheSHA(expected) + // OverlayFS may report different devices for an ordinary file and its + // parent. The no-follow read, owner/link checks and the exact saved + // device+inode in each subsequent frame protect the actual file identity. + if err != nil || !sameBytes || !sameMode || !sameSize || !sameDigest { + t.Fatalf("canonical assessment cache differs: marshal=%t bytes=%t mode=%t size=%t digest=%t", err == nil, sameBytes, sameMode, sameSize, sameDigest) + } + if !existed { + for _, stamp := range []syscall.Timespec{file.Modified, file.Changed} { + when := time.Unix(stamp.Sec, stamp.Nsec) + if stamp.Nsec < 0 || stamp.Nsec >= 1e9 || when.Before(probe.start) || when.After(probe.end) { + t.Fatal("cache file timestamps outside actual command") + } + } + } + paths := []string{} + if len(raw) > 0 { + var value any + if json.Unmarshal(raw, &value) != nil { + t.Fatal("public JSON") + } + probe.security(t, value, "$", subject, requirement, &paths) + } + sort.Strings(paths) + t.Logf("%s: scanner_calls=%d cache_files=%d security=%v", stage, probe.scanner.calls, len(entries), paths) + probe.before, probe.stage = after, probe.stage+1 +} + +func (probe *windDirectCacheProbe) security(t *testing.T, value any, path string, subject domain.SecuritySubject, requirement domain.SecurityRequirement, paths *[]string) { + t.Helper() + switch value := value.(type) { + case map[string]any: + for key, item := range value { + if key == "security" && item != nil { + raw, err := json.Marshal(item) + var assessment domain.SecurityAssessment + decoder := json.NewDecoder(bytes.NewReader(raw)) + decoder.DisallowUnknownFields() + if err != nil || decoder.Decode(&assessment) != nil || assessment.Validate(requirement, subject) != nil || (assessment.Evidence != domain.SecurityEvidenceCache && assessment.Evidence != domain.SecurityEvidenceLocalScan) { + t.Fatal("public security subject/evidence differs") + } + stored, found := (securityscan.FileCache{Root: filepath.Join(probe.root, "security", "assessments")}).Load(securityscan.CacheKey(subject, requirement)) + cleared := assessment + cleared.Evidence = "" + if !found || !reflect.DeepEqual(cleared, stored) { + t.Fatal("public security does not join the exact cache assessment") + } + *paths = append(*paths, path+"."+key+"="+string(assessment.Evidence)) + } + probe.security(t, item, path+"."+key, subject, requirement, paths) + } + case []any: + for _, item := range value { + probe.security(t, item, path+"[]", subject, requirement, paths) + } + } +} diff --git a/cli/cmd/agentplugins/devin_project_direct_cache_contract_linux_test.go b/cli/cmd/agentplugins/devin_project_direct_cache_contract_linux_test.go new file mode 100644 index 000000000..6c76b9a95 --- /dev/null +++ b/cli/cmd/agentplugins/devin_project_direct_cache_contract_linux_test.go @@ -0,0 +1,310 @@ +//go:build linux + +package main + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "os" + "path/filepath" + "reflect" + "strings" + "testing" + "time" + + "github.com/777genius/plugin-kit-ai/cli/internal/agentpluginscli" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/domain" +) + +type devinDirectOwned struct { + installation domain.Installation + binding domain.ClientBinding +} + +// Existing Devin journeys cover transport/recovery. This closes the distinct +// direct-local public DTO and receipt-history contract without a native client. +func TestProjectDevinDirectDefaultCacheLifecycleStages(t *testing.T) { + f, cache := newWindDirectCacheJourney(t) + sourceA, sourceB := projectJourneyTemp(t), projectJourneyTemp(t) + write := func(root, version, skill, endpoint string) { + t.Helper() + projectJourneyWrite(t, filepath.Join(root, "plugin.json"), `{"$schema":"https://agent-plugins.org/schemas/1.0.0/plugin.schema.json","name":"docs","version":"`+version+`"}`) + projectJourneyWrite(t, filepath.Join(root, "skills", "docs", "SKILL.md"), skill) + projectJourneyWrite(t, filepath.Join(root, "mcp.json"), `{"$schema":"https://agent-plugins.org/schemas/1.0.0/mcp.schema.json","mcpServers":{"docs":{"type":"streamable-http","url":"`+endpoint+`"}}}`) + } + write(sourceA, "1.0.0", projectJourneySkill, "http://127.0.0.1:9/a-one") + write(sourceB, "1.0.0", projectJourneySkill, "http://127.0.0.1:9/b-one") + user := securityFixtureTree(t, f.devinRoot("")) + marker := filepath.Join(f.namespace(f.a), "plugin-data", "foreign", "keep.txt") + projectJourneyWrite(t, marker, "unrelated caller data\n") + latest := map[string]devinDirectOwned{} + var bTree map[string]string + run := func(stage, verb, project, source, version string, mutated bool) { + t.Helper() + previous := latest[project] + statePath := filepath.Join(f.namespace(project), "state-v2.json") + var oldState string + var oldNative, oldPackage map[string]string + if !mutated { + oldState = projectJourneyRead(t, statePath) + oldNative = securityFixtureTree(t, f.devinRoot(project)) + oldPackage = securityFixtureTree(t, previous.binding.TargetLocator) + } + selector := previous.installation.InstallationID + if verb == "add" { + selector = source + } + cache.start = time.Now() + time.Sleep(20 * time.Millisecond) + raw := devinDirectExecute(t, f, project, verb, selector) + cache.end = time.Now() + state := f.state(t, project) + if len(state.Installations) != 1 || len(state.EnvironmentReceipts) != 0 { + t.Fatal("direct no-save state membership differs", stage) + } + current := devinDirectOwned{installation: state.Installations[0]} + if verb == "remove" { + devinDirectRemoved(t, f, project, previous, state) + current.binding = previous.binding + } else { + if len(current.installation.Clients) != 1 || len(current.installation.DataReceipts) != 0 || len(state.TransactionReceipts) != 0 { + t.Fatal("remote recipe unexpected binding/data/transaction state", stage) + } + for _, binding := range current.installation.Clients { + current.binding = binding + } + devinDirectBinding(t, f, project, source, version, previous, current, mutated) + } + devinDirectDTO(t, raw, stage, verb, version, current, mutated) + cache.observe(t, stage, raw, current.installation) + if !mutated && (oldState != projectJourneyRead(t, statePath) || !reflect.DeepEqual(oldNative, securityFixtureTree(t, f.devinRoot(project))) || !reflect.DeepEqual(oldPackage, securityFixtureTree(t, previous.binding.TargetLocator))) { + t.Fatal("direct no-op rewrote state/native/payload", stage) + } + if !reflect.DeepEqual(user, securityFixtureTree(t, f.devinRoot(""))) || projectJourneyRead(t, marker) != "unrelated caller data\n" { + t.Fatal("direct project lifecycle changed User or unrelated data", stage) + } + if project == f.a && bTree != nil && !reflect.DeepEqual(bTree, securityFixtureTree(t, f.b)) { + t.Fatal("direct A operation changed complete original B", stage) + } + latest[project] = current + t.Logf("%s: binding_receipts=%d transaction_receipts=%d data_retained=%t", stage, len(current.binding.Receipts), len(state.TransactionReceipts), current.installation.DataRetained) + } + run("add-a", "add", f.a, sourceA, "1.0.0", true) + run("add-b", "add", f.b, sourceB, "1.0.0", true) + if latest[f.a].installation.InstallationID == latest[f.b].installation.InstallationID || latest[f.a].binding.PhysicalArtifact == latest[f.b].binding.PhysicalArtifact { + t.Fatal("same-name direct scopes share installation/physical authority") + } + bTree = securityFixtureTree(t, f.b) + run("repeat-add-a", "add", f.a, sourceA, "1.0.0", false) + run("unchanged-update-a", "update", f.a, sourceA, "1.0.0", false) + run("intact-repair-a", "repair", f.a, sourceA, "1.0.0", true) + write(sourceA, "1.1.0", projectJourneyAdvancedSkill, "http://127.0.0.1:9/a-two") + run("update-a", "update", f.a, sourceA, "1.1.0", true) + active := latest[f.a].binding.TargetLocator + managed := securityFixtureTree(t, active) + config := projectJourneyRead(t, filepath.Join(f.devinRoot(f.a), "mcp_config.json")) + if projectJourneyRead(t, filepath.Join(f.devinRoot(f.a), "skills", "docs", "SKILL.md")) != projectJourneyAdvancedSkill { + t.Fatal("owned native skill does not match the exact fault recipe") + } + if err := os.RemoveAll(filepath.Join(f.devinRoot(f.a), "skills", "docs")); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(managed, securityFixtureTree(t, active)) || projectJourneyRead(t, filepath.Join(f.devinRoot(f.a), "mcp_config.json")) != config { + t.Fatal("native skill absence fault changed managed payload/MCP") + } + run("missing-repair-a", "repair", f.a, sourceA, "1.1.0", true) + run("remove-a", "remove", f.a, sourceA, "1.1.0", true) + before := projectJourneyRead(t, filepath.Join(f.namespace(f.a), "state-v2.json")) + cache.start = time.Now() + time.Sleep(20 * time.Millisecond) + if _, err := f.execute(f.a, "remove", latest[f.a].installation.InstallationID, "--target", "windsurf"); err == nil || err.Error() != `plugin is not installed for target "windsurf" in project scope; no target was changed` { + t.Fatal("direct repeated removal refusal differs", err) + } + cache.end = time.Now() + if before != projectJourneyRead(t, filepath.Join(f.namespace(f.a), "state-v2.json")) || !reflect.DeepEqual(bTree, securityFixtureTree(t, f.b)) { + t.Fatal("direct repeated removal changed state or B") + } + cache.observe(t, "repeat-remove-a", nil, latest[f.a].installation) + afterA := securityFixtureTree(t, f.a) + run("remove-b", "remove", f.b, sourceB, "1.0.0", true) + if cache.stage != 10 || cache.scanner.calls != 3 { + t.Fatal("exact cache lifecycle stage/scan ledger differs") + } + if !reflect.DeepEqual(afterA, securityFixtureTree(t, f.a)) { + t.Fatal("B removal changed retained A") + } +} + +func devinDirectExecute(t *testing.T, f devinProjectJourney, project, verb, selector string) []byte { + t.Helper() + var stdout, stderr bytes.Buffer + app := f.app + app.Input, app.Output, app.ErrorOutput, app.Terminal = strings.NewReader(""), &stdout, &stderr, false + root := agentpluginscli.NewRoot(app) + args := []string{verb, selector, "--scope", "project", "--project-root", project, "--target", "windsurf", "--format", "json"} + if verb == "add" { + args = append(args, "--no-save") + } + root.SetArgs(args) + if err := root.Execute(); err != nil { + t.Fatalf("direct %s: %v\n%s\n%s", verb, err, stdout.String(), stderr.String()) + } + return stdout.Bytes() +} + +func devinDirectBinding(t *testing.T, f devinProjectJourney, project, source, version string, previous, current devinDirectOwned, mutated bool) { + t.Helper() + i, b := current.installation, current.binding + manifest := sha256.Sum256([]byte(projectJourneyRead(t, filepath.Join(source, "plugin.json")))) + if i.DeclaredName != "docs" || i.Source.CanonicalSource != source || i.Source.RequestedSource != source || i.Package.Version != version || i.Package.ManifestDigest != "sha256:"+hex.EncodeToString(manifest[:]) || b.ClientID != "windsurf" || b.Scope != "project" || b.NativeProfileRoot != f.devinRoot(project) || b.Activation != domain.ActivationPrepared || b.Verification != domain.VerificationInstalled || b.PackageRevision == nil || b.PackageRevision.Version != version || b.PackageRevision.TreeDigest != i.Source.TreeDigest || b.PackageRevision.ManifestDigest != i.Package.ManifestDigest { + t.Fatal("direct source/project/Prepared binding differs") + } + old := previous.binding + if previous.installation.InstallationID != "" && (previous.installation.InstallationID != i.InstallationID || old.ClientBindingID != b.ClientBindingID || old.PhysicalArtifact != b.PhysicalArtifact || old.TargetLocator != b.TargetLocator || previous.installation.Source.SourceBindingID != i.Source.SourceBindingID) { + t.Fatal("direct mutation changed held installation/binding/source identity") + } + added := 0 + if mutated { + added = 1 + } + if len(b.Receipts) != len(old.Receipts)+added || !reflect.DeepEqual(b.Receipts[:len(old.Receipts)], old.Receipts) && len(old.Receipts) != 0 { + t.Fatal("direct mutation rewrote receipt prefix/count") + } + if mutated { + r := b.Receipts[len(b.Receipts)-1] + if r.MutationType != "directory_swap" || r.Phase != "committed" || r.Sequence != len(b.Receipts) || r.ClientBindingID != b.ClientBindingID || r.ActivePath != b.TargetLocator || r.OperationGroupID != i.OperationGroupID || r.OperationID != i.OperationGroupID+"-001" || r.AfterDigest == "" { + t.Fatal("direct selected committed mutation receipt differs") + } + } + if previous.installation.Package.Version != "" && previous.installation.Package.Version != version && previous.installation.Source.TreeDigest == i.Source.TreeDigest { + t.Fatal("direct A version update did not advance source digest") + } + skill := projectJourneySkill + if version == "1.1.0" { + skill = projectJourneyAdvancedSkill + } + for _, root := range []string{b.TargetLocator, f.devinRoot(project)} { + if projectJourneyRead(t, filepath.Join(root, "skills", "docs", "SKILL.md")) != skill { + t.Fatal("direct managed/native selected skill bytes differ") + } + } + devinDirectForeign(t, f, project) +} + +func devinDirectForeign(t *testing.T, f devinProjectJourney, project string) { + t.Helper() + for _, path := range []string{filepath.Join(f.devinRoot(project), "skills", "foreign", "SKILL.md"), filepath.Join(f.devinRoot(project), "hooks.json")} { + want := "foreign skill\n" + if filepath.Base(path) == "hooks.json" { + want = "foreign hooks\n" + } + if projectJourneyRead(t, path) != want { + t.Fatal("direct mutation changed foreign native leaf") + } + } +} + +func devinDirectRemoved(t *testing.T, f devinProjectJourney, project string, previous devinDirectOwned, state domain.StateFileV2) { + t.Helper() + i, b := state.Installations[0], previous.binding + if i.InstallationID != previous.installation.InstallationID || !reflect.DeepEqual(i.Source, previous.installation.Source) || !reflect.DeepEqual(i.Package, previous.installation.Package) || len(i.Clients) != 0 || !i.DataRetained || len(i.DataReceipts) != 1 || len(state.TransactionReceipts) != 1 { + t.Fatal("direct default removal retained-data state differs") + } + r := state.TransactionReceipts[0] + if r.MutationType != "directory_remove" || r.Phase != "committed" || r.Sequence != len(b.Receipts)+1 || r.ClientBindingID != b.ClientBindingID || r.ActivePath != b.TargetLocator || r.OperationGroupID != i.OperationGroupID || r.OperationID != i.OperationGroupID+"-001" || r.BeforeDigest != b.Receipts[len(b.Receipts)-1].AfterDigest { + t.Fatal("direct state-level removal receipt differs") + } + projectJourneyAbsent(t, b.TargetLocator, filepath.Join(f.devinRoot(project), "skills", "docs")) + devinDirectForeign(t, f, project) + var native map[string]any + if json.Unmarshal([]byte(projectJourneyRead(t, filepath.Join(f.devinRoot(project), "mcp_config.json"))), &native) != nil || native["foreignPreference"] != "keep" || !reflect.DeepEqual(native["mcpServers"], map[string]any{"foreign": map[string]any{"url": "https://foreign.test/mcp", "disabled": true}}) { + t.Fatal("direct removal changed foreign native config or retained selected server") + } + for id, data := range i.DataReceipts { + var owner domain.DataReceipt + if id != data.DataReceiptID || data.PhysicalBackend != b.PhysicalArtifact || data.Scope != "project" || data.State != domain.DataReceiptOwned || data.Locator != filepath.Join(f.namespace(project), "plugin-data", b.PhysicalArtifact) || json.Unmarshal([]byte(projectJourneyRead(t, filepath.Join(data.Locator, ".agentplugins-data-owner.json"))), &owner) != nil || !reflect.DeepEqual(owner, data) { + t.Fatal("direct default removal ownership marker differs") + } + } +} + +func devinDirectDTO(t *testing.T, raw []byte, stage, verb, version string, selected devinDirectOwned, mutated bool) { + t.Helper() + var row map[string]any + if json.Unmarshal(raw, &row) != nil || len(row) != 4 || row["schema_version"] != float64(1) || row["command"] != verb || row["result"] != "success" { + t.Fatal("direct public envelope differs", stage) + } + data := row["data"].(map[string]any) + output := data + if stage == "repeat-add-a" { + if data["targets"] != nil || data["operation_id"] != nil { + t.Fatal("direct repeated add is not a singleton") + } + } else { + targets := data["targets"].([]any) + if data["batch"] != true || data["succeeded"] != float64(1) || data["failed"] != float64(0) || len(targets) != 1 || targets[0].(map[string]any)["target"] != "windsurf" || targets[0].(map[string]any)["status"] != "external_completed" { + t.Fatal("direct selected batch differs", stage) + } + output = targets[0].(map[string]any)["output"].(map[string]any) + if output["operation_id"] != data["operation_id"] || mutated && data["operation_id"] != selected.installation.OperationGroupID { + t.Fatal("direct selected operation group differs", stage) + } + if verb == "remove" && (data["status"] != "data_retained" || data["data_retained"] != true || data["plugin_data_preserved"] != true) { + t.Fatal("direct public default retention flags differ") + } + } + source := "direct local source" + if verb == "remove" || verb == "repair" { + source = "local" + } + if output["plugin"] != "docs" || output["version"] != version || output["source"] != source || output["tree_digest"] != selected.installation.Source.TreeDigest || output["manifest_digest"] != selected.installation.Package.ManifestDigest || output["dry_run"] != false { + t.Fatal("direct public source/revision differs", stage) + } + outcome := output["result"].(map[string]any) + keys := strings.Fields("installation_id requires_confirmation mutated") + if verb == "remove" { + keys = append(keys, strings.Fields("plugin client_id affected_surfaces deactivation group_phase")...) + if outcome["plugin"] != "docs" || outcome["client_id"] != "windsurf" || !reflect.DeepEqual(outcome["affected_surfaces"], []any{"windsurf"}) || !reflect.DeepEqual(outcome["deactivation"], map[string]any{"activation": "not_required", "artifact_removal_allowed": true, "external_removal_complete": true}) { + t.Fatal("direct removal deactivation differs") + } + } else { + keys = append(keys, "plan", "activation") + if stage != "repeat-add-a" { + keys = append(keys, "group_phase") + } + if stage == "repeat-add-a" || stage == "unchanged-update-a" { + keys = append(keys, "no_change") + if outcome["no_change"] != true { + t.Fatal("direct no-op lost no_change") + } + } + plan := outcome["plan"].(map[string]any) + activation := outcome["activation"].(map[string]any) + if plan["client_id"] != "windsurf" || plan["scope"] != "project" || plan["activation"] != "prepared" || plan["verification"] != "package_validated" || plan["physical_artifact_id"] != selected.binding.PhysicalArtifact || activation["activation"] != "prepared" || activation["authentication"] != "not_checked" || activation["policy"] != "allowed" || activation["verification"] != "installation_verified" { + t.Fatal("direct Prepared result differs") + } + components := plan["components"].([]any) + if len(components) != 2 { + t.Fatal("direct supported component inventory differs") + } + kinds := map[string]bool{"skill": true, "mcp_server": true} + for _, component := range components { + row := component.(map[string]any) + kind := row["kind"].(string) + if len(row) != 3 || row["name"] != "docs" || row["support"] != "prepared" || !kinds[kind] { + t.Fatal("direct project component differs", row) + } + delete(kinds, kind) + } + } + if len(outcome) != len(keys) || outcome["installation_id"] != selected.installation.InstallationID || outcome["requires_confirmation"] != false || outcome["mutated"] != mutated || stage != "repeat-add-a" && outcome["group_phase"] != "external_completed" { + t.Fatal("direct exact stage result shape differs", stage, outcome) + } + for _, key := range keys { + if _, present := outcome[key]; !present { + t.Fatal("direct stage result missing field", stage, key) + } + } +} diff --git a/cli/cmd/agentplugins/devin_project_version_test.go b/cli/cmd/agentplugins/devin_project_version_test.go new file mode 100644 index 000000000..3378694e9 --- /dev/null +++ b/cli/cmd/agentplugins/devin_project_version_test.go @@ -0,0 +1,208 @@ +package main + +import ( + "context" + "errors" + "fmt" + "path/filepath" + "reflect" + "strings" + "testing" + + "github.com/777genius/plugin-kit-ai/cli/internal/agentpluginscli" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/domain" +) + +// Plain discovery has no version and no Cascade profile. Only the explicitly +// selected inert callback can supply the observed current Devin version. +type devinProjectVersionDetector struct { + executable string + targeted [][]domain.ClientID + broad int + probeError error +} + +func (d *devinProjectVersionDetector) Detect(context.Context) ([]domain.DetectedClient, error) { + return []domain.DetectedClient{{ClientID: domain.ClientWindsurf, ExecutablePath: d.executable, Status: domain.DetectionDetected}}, nil +} + +func (d *devinProjectVersionDetector) DetectWithVersionProbe(ctx context.Context) ([]domain.DetectedClient, error) { + d.broad++ + rows, err := d.Detect(ctx) + if err != nil { + return rows, err + } + return rows, fmt.Errorf("fixture refuses broad version execution") +} + +func (d *devinProjectVersionDetector) DetectTargetsWithVersionProbe(ctx context.Context, targets []domain.ClientID) ([]domain.DetectedClient, error) { + d.targeted = append(d.targeted, append([]domain.ClientID(nil), targets...)) + if d.probeError != nil { + return nil, d.probeError + } + clients, err := d.Detect(ctx) + if err != nil { + return nil, err + } + clients[0].Version = "3000.11.205" + return clients, nil +} + +func (d *devinProjectVersionDetector) assertCalls(t *testing.T, before, added int) { + t.Helper() + if d.broad != 0 || len(d.targeted) != before+added { + t.Fatalf("Devin version execution differs: broad=%d targeted=%v, want %d new selected calls", d.broad, d.targeted, added) + } + for _, targets := range d.targeted { + if !reflect.DeepEqual(targets, []domain.ClientID{domain.ClientWindsurf}) { + t.Fatalf("unselected client reached Devin version execution: %v", targets) + } + } +} + +func configureDevinVersionJourney(app agentpluginscli.App, detector *devinProjectVersionDetector) agentpluginscli.App { + app.Detector = detector + compose := app.ForScope + app.ForScope = func(scope domain.InstallScope, root string) (agentpluginscli.App, error) { + selected, err := compose(scope, root) + if err != nil { + return selected, err + } + return configureDevinVersionJourney(selected, detector), nil + } + return app +} + +func devinVersionOwned(t *testing.T, f devinProjectJourney, skill string, saved bool) (domain.Installation, domain.ClientBinding) { + t.Helper() + state := f.state(t, f.a) + receipts := 0 + if saved { + receipts = 1 + } + if len(state.Installations) != 1 || len(state.Installations[0].Clients) != 1 || len(state.EnvironmentReceipts) != receipts { + t.Fatalf("Devin version lifecycle lost exact local/saved ownership: %+v", state) + } + installation := state.Installations[0] + for _, binding := range installation.Clients { + if binding.ClientID != "windsurf" || binding.Scope != "project" || binding.NativeProfileRoot != f.devinRoot(f.a) || binding.Activation != domain.ActivationPrepared || binding.Verification != domain.VerificationInstalled { + t.Fatalf("version observation changed Devin project authority: %+v", binding) + } + for _, root := range []string{binding.TargetLocator, f.devinRoot(f.a)} { + if projectJourneyRead(t, filepath.Join(root, "skills", "docs", "SKILL.md")) != skill { + t.Fatal("Devin managed/native selected bytes differ") + } + } + return installation, binding + } + t.Fatal("Devin project binding missing") + return domain.Installation{}, domain.ClientBinding{} +} + +func TestProjectDevinEmptyVersionSelectedLifecycle(t *testing.T) { + for _, saved := range []bool{false, true} { + name := "direct-local" + if saved { + name = "saved-tls-zip" + } + t.Run(name, func(t *testing.T) { + transport := newProjectJourneyTransport(t, "zip") + devinProjectCommitSource(t, transport, projectJourneySkill, "https://managed.test/v1") + f := newDevinProjectJourney(t, transport) + detector := &devinProjectVersionDetector{executable: filepath.Join(f.home, ".devin", "devin")} + f.app = configureDevinVersionJourney(f.app, detector) + userBefore := securityFixtureTree(t, f.devinRoot("")) + add := []string{"add", transport.repo, "--no-save", "--target", "devin"} + selector := "docs" + if saved { + add = []string{"add", transport.endpoint, "--alias", "docs", "--target", "windsurf"} + } + for _, root := range []string{f.a, f.b} { + before := len(detector.targeted) + f.run(t, root, add...) + detector.assertCalls(t, before, 1) + } + installation, binding := devinVersionOwned(t, f, projectJourneySkill, saved) + if !saved { + selector = installation.InstallationID + } + // This source uses remote MCP configuration and allocates no plugin + // data receipt. Preserve an existing unrelated data member instead. + dataPath := filepath.Join(f.namespace(f.a), "plugin-data", "foreign", "keep.txt") + projectJourneyWrite(t, dataPath, "retained unrelated data\n") + bBefore := securityFixtureTree(t, f.b) + preserved := func() { + t.Helper() + if !reflect.DeepEqual(userBefore, securityFixtureTree(t, f.devinRoot(""))) || !reflect.DeepEqual(bBefore, securityFixtureTree(t, f.b)) { + t.Fatal("version-assisted A lifecycle changed original user or project B") + } + if projectJourneyRead(t, dataPath) != "retained unrelated data\n" { + t.Fatal("version-assisted Devin lifecycle changed unrelated persistent data") + } + } + if saved { + before := len(detector.targeted) + state := projectJourneyRead(t, filepath.Join(f.namespace(f.a), "state-v2.json")) + f.run(t, f.a, "deps", "sync", "--locked", "--yes") + detector.assertCalls(t, before, 0) + if state != projectJourneyRead(t, filepath.Join(f.namespace(f.a), "state-v2.json")) { + t.Fatal("unchanged Devin reconciliation changed ownership state") + } + } + for _, args := range [][]string{{"list"}, {"info", installation.InstallationID}, {"doctor"}} { + before := len(detector.targeted) + f.run(t, f.a, args...) + detector.assertCalls(t, before, 0) + } + for _, args := range [][]string{{"update", selector, "--target", "windsurf", "--dry-run"}, {"repair", installation.InstallationID, "--target", "windsurf", "--dry-run"}} { + before, snapshot := len(detector.targeted), securityFixtureTree(t, f.a) + _, err := f.execute(f.a, args...) + if err != nil && !strings.Contains(err.Error(), "explicitly selected primary") { + t.Fatal(err) + } + detector.assertCalls(t, before, 0) + if !reflect.DeepEqual(snapshot, securityFixtureTree(t, f.a)) { + t.Fatal("Devin dry-run changed project authority") + } + } + before := len(detector.targeted) + f.run(t, f.a, "repair", installation.InstallationID, "--target", "windsurf") + detector.assertCalls(t, before, 1) + devinVersionOwned(t, f, projectJourneySkill, saved) + preserved() + devinProjectCommitSource(t, transport, projectJourneyAdvancedSkill, "https://managed.test/v2") + before = len(detector.targeted) + f.run(t, f.a, "update", selector, "--target", "windsurf") + detector.assertCalls(t, before, 1) + updated, current := devinVersionOwned(t, f, projectJourneyAdvancedSkill, saved) + if updated.Source.TreeDigest == installation.Source.TreeDigest || current.ClientBindingID != binding.ClientBindingID || current.TargetLocator != binding.TargetLocator { + t.Fatal("Devin update lost source or selected binding identity") + } + if !reflect.DeepEqual(installation.DataReceipts, updated.DataReceipts) { + t.Fatal("remote MCP update changed the existing data receipt set") + } + preserved() + before = len(detector.targeted) + f.run(t, f.a, "remove", selector, "--target", "windsurf") + detector.assertCalls(t, before, 0) + projectJourneyAbsent(t, binding.TargetLocator, filepath.Join(f.devinRoot(f.a), "skills", "docs")) + preserved() + }) + } +} + +func TestProjectDevinEmptyVersionFailedObservationPreservesScopes(t *testing.T) { + transport := newProjectJourneyTransport(t, "zip") + devinProjectCommitSource(t, transport, projectJourneySkill, "https://managed.test/v1") + f := newDevinProjectJourney(t, transport) + detector := &devinProjectVersionDetector{executable: filepath.Join(f.home, ".devin", "devin"), probeError: errors.New("inert selected Devin version failure")} + f.app = configureDevinVersionJourney(f.app, detector) + a, b, user := securityFixtureTree(t, f.a), securityFixtureTree(t, f.b), securityFixtureTree(t, f.devinRoot("")) + if _, err := f.execute(f.a, "add", transport.repo, "--no-save", "--target", "windsurf"); err == nil || !strings.Contains(err.Error(), "inert selected Devin version failure") { + t.Fatalf("failed selected version was not surfaced: %v", err) + } + detector.assertCalls(t, 0, 1) + if !reflect.DeepEqual(a, securityFixtureTree(t, f.a)) || !reflect.DeepEqual(b, securityFixtureTree(t, f.b)) || !reflect.DeepEqual(user, securityFixtureTree(t, f.devinRoot(""))) { + t.Fatal("failed selected Devin version changed project or original-user authority") + } +} diff --git a/cli/cmd/agentplugins/package_manager_install_fixture_test.go b/cli/cmd/agentplugins/package_manager_install_fixture_test.go index 672588a08..a66f120c8 100644 --- a/cli/cmd/agentplugins/package_manager_install_fixture_test.go +++ b/cli/cmd/agentplugins/package_manager_install_fixture_test.go @@ -404,7 +404,7 @@ func (f pmInstallJourney) assertInstalled(t *testing.T, project, target, revisio for _, receipt := range installation.DataReceipts { data = receipt.Locator } - if !reflect.DeepEqual(worker["args"], []any{"--internal-stdio-v1", binding.TargetLocator, data, binding.TargetLocator, "plugin", "--", "go", "version"}) { + if !reflect.DeepEqual(worker["args"], []any{"--internal-stdio-v1", binding.TargetLocator, data, binding.TargetLocator, "plugin", "--argv-base64-v1", "Z28=", "dmVyc2lvbg=="}) { t.Fatalf("Cursor launcher bindings=%+v", worker) } env, ok := worker["env"].(map[string]any) diff --git a/cli/cmd/agentplugins/project_cline_cli_presence_test.go b/cli/cmd/agentplugins/project_cline_cli_presence_test.go new file mode 100644 index 000000000..3929ba2c6 --- /dev/null +++ b/cli/cmd/agentplugins/project_cline_cli_presence_test.go @@ -0,0 +1,157 @@ +package main + +import ( + "context" + "encoding/json" + "errors" + "os" + "os/exec" + "path/filepath" + "reflect" + "strings" + "testing" + + "github.com/777genius/plugin-kit-ai/cli/internal/agentpluginscli" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/adapters/clientdetect" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/adapters/specregistry" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/domain" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/installer" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/ports" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/providers" +) + +func TestProjectClineStandaloneCLIPresenceAllowsFileOnlyLocalAddRemove(t *testing.T) { + t.Setenv("CLINE_MCP_SETTINGS_PATH", "") + t.Setenv("CLINE_DATA_DIR", "") + journey := projectJourney{home: projectJourneyTemp(t), a: projectJourneyTemp(t), b: projectJourneyTemp(t)} + journey.cache = filepath.Join(journey.home, "uap") + source := projectJourneyTemp(t) + projectJourneyWrite(t, filepath.Join(source, "plugin.json"), `{"$schema":"https://agent-plugins.org/schemas/1.0.0/plugin.schema.json","name":"cline-presence","version":"1.0.0"}`) + projectJourneyWrite(t, filepath.Join(source, "skills", "docs", "SKILL.md"), projectJourneySkill) + projectJourneyWrite(t, filepath.Join(source, "mcp.json"), `{"$schema":"https://agent-plugins.org/schemas/1.0.0/mcp.schema.json","mcpServers":{"docs":{"type":"stdio","command":"node","args":["${PLUGIN_ROOT}/server.js"],"cwd":"${PLUGIN_ROOT}"}}}`) + projectJourneyWrite(t, filepath.Join(source, "server.js"), "inert source bytes; never executed\n") + if err := os.Mkdir(filepath.Join(journey.a, ".git"), 0700); err != nil { + t.Fatal(err) + } + user := filepath.Join(journey.home, ".cline") + projectJourneyWrite(t, filepath.Join(user, "data", "settings", "cline_mcp_settings.json"), `{"mcpServers":{"foreign-user":{"command":"/never-run","args":[],"disabled":true}}}`) + projectJourneyWrite(t, filepath.Join(user, "skills", "foreign-user", "SKILL.md"), "original user skill\n") + projectJourneyWrite(t, filepath.Join(journey.b, ".cline", "skills", "foreign-b", "SKILL.md"), "other project skill\n") + projectJourneyWrite(t, filepath.Join(journey.b, ".uap", "keep"), "other project authority\n") + foreignA := filepath.Join(journey.a, ".cline", "skills", "foreign-a", "SKILL.md") + projectJourneyWrite(t, foreignA, "foreign A skill\n") + siblingA := filepath.Join(journey.a, ".gemini", "keep") + projectJourneyWrite(t, siblingA, "other A client\n") + beforeUser, beforeB := securityFixtureTree(t, user), securityFixtureTree(t, journey.b) + schemas, err := specregistry.New() + if err != nil { + t.Fatal(err) + } + app, err := newAgentpluginsCLIApp(journey.home, journey.cache, nil, nil, nil, schemas) + if err != nil { + t.Fatal(err) + } + runner := &projectClineNoNative{} + probes, lookups := 0, 0 + var configure func(agentpluginscli.App) agentpluginscli.App + configure = func(app agentpluginscli.App) agentpluginscli.App { + detector := clientdetect.NewOS(journey.home) + detector.Registry, detector.Environment = app.ClientRegistry, map[string]string{} + detector.LookPath = func(name string) (string, error) { + if name == "cline" { + lookups++ + return filepath.Join(journey.home, "inert-bin", "cline"), nil + } + return "", exec.ErrNotFound + } + detector.ProbeVersionWithEnvironment = func(context.Context, string, []string) (string, error) { + probes++ + return "", errors.New("presence-only Cline must not execute a version probe") + } + app.Detector = detector + app.SecurityIndex, app.DirectoryClient, app.DiscoveryClient = nil, nil, nil + app.SecurityEvaluator = projectJourneySecurity{} + app.SecurityEvaluatorForDryRun = func(string) ports.PackageSecurityEvaluator { return projectJourneySecurity{} } + helper, err := os.Executable() + if err != nil { + t.Fatal(err) + } + engine, err := installer.New(installer.Config{StateRoot: filepath.Dir(app.ManagedRoot), ManagedRoot: app.ManagedRoot, ProjectRoot: app.ProjectRoot, Registry: app.ClientRegistry, Runner: runner, EnableNativeObserver: true, HelperExecutable: helper}) + if err != nil { + t.Fatal(err) + } + app.Installer = engine + activator, ok := app.Lifecycle.Activator.(providers.Activator) + if !ok { + t.Fatal("production Cline activator missing") + } + activator.Runner = runner + app.Lifecycle.Activator = activator + observer, ok := app.Lifecycle.NativeObserver.(providers.NativeIdentityObserver) + if !ok { + t.Fatal("production Cline native observer missing") + } + observer.Runner = runner + app.Lifecycle.NativeObserver = observer + compose := app.ForScope + app.ForScope = func(scope domain.InstallScope, root string) (agentpluginscli.App, error) { + selected, err := compose(scope, root) + if err != nil { + return selected, err + } + return configure(selected), nil + } + return app + } + journey.app = configure(app) + output := journey.run(t, journey.a, "add", source, "--no-save", "--target", "cline") + if !strings.Contains(output, `"activation":"prepared"`) || !strings.Contains(output, `"verification":"installation_verified"`) { + t.Fatal("public add did not retain Prepared file-delivery result", output) + } + state := journey.state(t, journey.a) + if len(state.Installations) != 1 || len(state.EnvironmentReceipts) != 0 { + t.Fatalf("local no-save route changed ownership: %+v", state) + } + installation := state.Installations[0] + if installation.Source.CanonicalSource != source || len(installation.Clients) != 1 { + t.Fatal("local source or exact selected binding changed") + } + var selected domain.ClientBinding + for _, binding := range installation.Clients { + selected = binding + if binding.ClientID != "cline" || binding.Scope != "project" || binding.NativeProfileRoot != journey.a || binding.Activation != domain.ActivationPrepared || binding.Verification != domain.VerificationInstalled || len(binding.NativeObjects) != 3 { + t.Fatalf("file-only project authority differs: %+v", binding) + } + } + if projectJourneyRead(t, filepath.Join(journey.a, ".cline", "skills", "docs", "SKILL.md")) != projectJourneySkill || !strings.Contains(projectJourneyRead(t, filepath.Join(journey.a, ".uap", "clients", "cline", "mcp.json")), `"docs"`) { + t.Fatal("actual project skill/MCP delivery missing") + } + journey.run(t, journey.a, "remove", installation.InstallationID, "--target", "cline") + projectJourneyAbsent(t, selected.TargetLocator, filepath.Join(journey.a, ".cline", "skills", "docs"), filepath.Join(journey.cache, "state-v2.json"), filepath.Join(journey.home, ".vscode"), filepath.Join(journey.home, ".cursor")) + if !reflect.DeepEqual(beforeUser, securityFixtureTree(t, user)) || !reflect.DeepEqual(beforeB, securityFixtureTree(t, journey.b)) || projectJourneyRead(t, foreignA) != "foreign A skill\n" || projectJourneyRead(t, siblingA) != "other A client\n" { + t.Fatal("CLI-only project delivery changed original user, sibling project or foreign client facts") + } + config, err := os.ReadFile(filepath.Join(journey.a, ".uap", "clients", "cline", "mcp.json")) + if err != nil && !os.IsNotExist(err) { + t.Fatal(err) + } + if err == nil { + var document struct { + Servers map[string]json.RawMessage `json:"mcpServers"` + } + if err := json.Unmarshal(config, &document); err != nil { + t.Fatal(err) + } + if _, exists := document.Servers["docs"]; exists { + t.Fatal("removed project retained its owned MCP docs member") + } + } + for _, remaining := range journey.state(t, journey.a).Installations { + if len(remaining.Clients) != 0 { + t.Fatalf("removed project retained a client binding: %+v", remaining.Clients) + } + } + if lookups == 0 || probes != 0 || runner.calls != 0 { + t.Fatalf("presence-only native boundary differs: lookups=%d probes=%d calls=%d", lookups, probes, runner.calls) + } +} diff --git a/cli/cmd/agentplugins/project_kimi_intact_repair_test.go b/cli/cmd/agentplugins/project_kimi_intact_repair_test.go new file mode 100644 index 000000000..77c9a9a1d --- /dev/null +++ b/cli/cmd/agentplugins/project_kimi_intact_repair_test.go @@ -0,0 +1,89 @@ +package main + +import ( + "encoding/json" + "os" + "path/filepath" + "reflect" + "strings" + "testing" + + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/domain" +) + +// Exercise the public App with an intact recorded artifact. The existing +// damaged-pin repair regression deliberately takes a different selection path. +func TestProjectKimiPublicIntactRepairPreservesMCPSelection(t *testing.T) { + transport := newProjectJourneyTransport(t, "zip") + journey := newProjectJourney(t, transport) + user := filepath.Join(journey.home, ".kimi-code") + journey.app = configureProjectKimiJourney(journey.app, user, filepath.Join(journey.home, "kimi")) + for _, project := range []string{journey.a, journey.b} { + if err := os.Mkdir(filepath.Join(project, ".git"), 0700); err != nil { + t.Fatal(err) + } + projectJourneyWrite(t, filepath.Join(project, ".kimi-code", "mcp.json"), kimiIntactForeign) + journey.run(t, project, "add", transport.repo, "--target", "kimi", "--no-save") + } + projectJourneyWrite(t, filepath.Join(user, "mcp.json"), kimiIntactForeign) + installation, binding := projectKimiVersionOwned(t, journey, projectJourneySkill, false) + projectJourneyDataMarker(t, journey, journey.a, installation) + beforeUser, beforeB := securityFixtureTree(t, user), securityFixtureTree(t, journey.b) + mcp := filepath.Join(journey.a, ".kimi-code", "mcp.json") + skill := filepath.Join(journey.a, ".kimi-code", "skills", "docs", "SKILL.md") + beforeMCP, beforeSkill := projectJourneyRead(t, mcp), projectJourneyRead(t, skill) + output := journey.run(t, journey.a, "repair", installation.InstallationID, "--target", "kimi") + projectKimiIntactRepairSelection(t, output, installation.InstallationID) + if projectJourneyRead(t, mcp) != beforeMCP || projectJourneyRead(t, skill) != beforeSkill { + t.Fatal("intact public repair changed native skill or MCP bytes") + } + if strings.Contains(output, "not_in_recorded_delivery") || strings.Contains(output, "managed_component_removal_planned") { + t.Fatal("intact public repair discarded recorded project MCP selection") + } + after, repaired := projectKimiVersionOwned(t, journey, projectJourneySkill, false) + if after.InstallationID != installation.InstallationID || !reflect.DeepEqual(after.Source, installation.Source) || !reflect.DeepEqual(after.Package, installation.Package) || repaired.ClientBindingID != binding.ClientBindingID || repaired.PhysicalArtifact != binding.PhysicalArtifact || repaired.DataReceiptID != binding.DataReceiptID || !reflect.DeepEqual(repaired.NativeObjects, binding.NativeObjects) { + t.Fatal("intact repair changed held installation, binding, data or native ownership") + } + if !reflect.DeepEqual(beforeUser, securityFixtureTree(t, user)) || !reflect.DeepEqual(beforeB, securityFixtureTree(t, journey.b)) { + t.Fatal("intact repair changed original user or B") + } + for _, receipt := range installation.DataReceipts { + if projectJourneyRead(t, filepath.Join(receipt.Locator, "keep.txt")) != "retained environment data\n" { + t.Fatal("intact repair changed retained data") + } + } +} + +func projectKimiIntactRepairSelection(t *testing.T, output, installationID string) { + t.Helper() + var envelope struct { + Data struct { + Targets []struct { + Target string `json:"target"` + Output struct { + Result struct { + InstallationID string `json:"installation_id"` + Plan domain.DeliveryPlan `json:"plan"` + } `json:"result"` + } `json:"output"` + } `json:"targets"` + } `json:"data"` + } + // The journey helper appends diagnostic stderr after the JSON stdout. + if err := json.NewDecoder(strings.NewReader(output)).Decode(&envelope); err != nil || len(envelope.Data.Targets) != 1 { + t.Fatal("public repair did not return one target result", err) + } + target := envelope.Data.Targets[0] + plan := target.Output.Result.Plan + if target.Target != "kimi" || target.Output.Result.InstallationID != installationID || plan.Scope != domain.ScopeProject || plan.ClientID != domain.ClientKimi { + t.Fatal("public repair changed explicit selected identity") + } + for _, component := range plan.Components { + if component.Kind == domain.ComponentMCPServer && component.Name == "docs" && component.Support == domain.SupportNative && component.Reason == "" { + return + } + } + t.Fatal("public repair did not preserve the recorded native MCP component") +} + +const kimiIntactForeign = `{"mcpServers":{"foreign":{"transport":"http","url":"https://foreign.test/mcp","enabled":false}},"policy":"keep"}` diff --git a/cli/cmd/agentplugins/project_kimi_version_fixture_test.go b/cli/cmd/agentplugins/project_kimi_version_fixture_test.go new file mode 100644 index 000000000..2943e11e8 --- /dev/null +++ b/cli/cmd/agentplugins/project_kimi_version_fixture_test.go @@ -0,0 +1,126 @@ +package main + +import ( + "context" + "fmt" + "os" + "path/filepath" + "reflect" + "testing" + + "github.com/777genius/plugin-kit-ai/cli/internal/agentpluginscli" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/domain" +) + +// This is an inert detector. A plain discovery never knows the client version; +// only the exact selected probe supplies it. No client executable is invoked. +type projectKimiVersionDetector struct { + user, executable string + targeted [][]domain.ClientID + broad int + probeError error + geminiError error +} + +func (d *projectKimiVersionDetector) Detect(context.Context) ([]domain.DetectedClient, error) { + return []domain.DetectedClient{ + {ClientID: domain.ClientKimi, ConfigRoot: d.user, ExecutablePath: d.executable, Status: domain.DetectionDetected}, + {ClientID: domain.ClientGemini, ConfigRoot: filepath.Join(filepath.Dir(d.user), ".gemini"), Status: domain.DetectionDetected, DetectionError: d.geminiError}, + }, nil +} + +func (d *projectKimiVersionDetector) DetectWithVersionProbe(ctx context.Context) ([]domain.DetectedClient, error) { + d.broad++ + rows, err := d.Detect(ctx) + if err != nil { + return rows, err + } + return rows, fmt.Errorf("fixture refuses broad version execution") +} + +func (d *projectKimiVersionDetector) DetectTargetsWithVersionProbe(ctx context.Context, targets []domain.ClientID) ([]domain.DetectedClient, error) { + d.targeted = append(d.targeted, append([]domain.ClientID(nil), targets...)) + if d.probeError != nil { + return nil, d.probeError + } + clients, err := d.Detect(ctx) + if err != nil { + return nil, err + } + for i := range clients { + for _, target := range targets { + if clients[i].ClientID == target && target == domain.ClientKimi { + clients[i].Version = "2.3.1" + } + } + } + return clients, nil +} + +func (d *projectKimiVersionDetector) assertCalls(t *testing.T, before, added int) { + t.Helper() + if d.broad != 0 || len(d.targeted) != before+added { + t.Fatalf("version execution differs: broad=%d targeted=%v; wanted %d new selected calls", d.broad, d.targeted, added) + } + for _, targets := range d.targeted { + if !reflect.DeepEqual(targets, []domain.ClientID{domain.ClientKimi}) { + t.Fatalf("unselected client reached version execution: %v", targets) + } + } +} + +func configureProjectKimiVersionJourney(app agentpluginscli.App, detector *projectKimiVersionDetector) agentpluginscli.App { + app.Detector = detector + compose := app.ForScope + app.ForScope = func(scope domain.InstallScope, root string) (agentpluginscli.App, error) { + selected, err := compose(scope, root) + if err != nil { + return selected, err + } + return configureProjectKimiVersionJourney(selected, detector), nil + } + return app +} + +func newProjectKimiVersionJourney(t *testing.T) (projectJourney, *projectKimiVersionDetector) { + t.Helper() + journey := newProjectJourney(t, newProjectJourneyTransport(t, "git")) + detector := &projectKimiVersionDetector{user: filepath.Join(journey.home, ".kimi-code"), executable: filepath.Join(journey.home, "kimi")} + journey.app = configureProjectKimiVersionJourney(journey.app, detector) + for _, project := range []string{journey.a, journey.b} { + if err := os.Mkdir(filepath.Join(project, ".git"), 0700); err != nil { + t.Fatal(err) + } + } + for _, root := range []string{detector.user, filepath.Join(journey.a, ".kimi-code"), filepath.Join(journey.b, ".kimi-code")} { + projectJourneyWrite(t, filepath.Join(root, "mcp.json"), `{"mcpServers":{"foreign":{"transport":"http","url":"https://foreign.test/mcp","enabled":false}},"policy":"keep"}`) + projectJourneyWrite(t, filepath.Join(root, "skills", "foreign", "SKILL.md"), "foreign Kimi skill\n") + } + return journey, detector +} + +func projectKimiVersionOwned(t *testing.T, journey projectJourney, expected string, saved bool) (domain.Installation, domain.ClientBinding) { + t.Helper() + state := journey.state(t, journey.a) + receipts := 0 + if saved { + receipts = 1 + } + if len(state.Installations) != 1 || len(state.Installations[0].Clients) != 1 || len(state.EnvironmentReceipts) != receipts { + t.Fatalf("Kimi lifecycle lost exact local/saved ownership: %+v", state) + } + installation := state.Installations[0] + for _, binding := range installation.Clients { + if binding.ClientID != "kimi" || binding.Scope != "project" || binding.NativeProfileRoot != filepath.Join(journey.a, ".kimi-code") || binding.Activation != domain.ActivationPrepared || binding.Verification != domain.VerificationInstalled { + t.Fatalf("version discovery changed Kimi project authority: %+v", binding) + } + for _, root := range []string{binding.TargetLocator, binding.NativeProfileRoot} { + if projectJourneyRead(t, filepath.Join(root, "skills", "docs", "SKILL.md")) != expected { + t.Fatal("Kimi selected managed/native bytes differ") + } + } + return installation, binding + } + t.Fatal("Kimi binding missing") + return domain.Installation{}, domain.ClientBinding{} +} diff --git a/cli/cmd/agentplugins/project_kimi_version_lifecycle_test.go b/cli/cmd/agentplugins/project_kimi_version_lifecycle_test.go new file mode 100644 index 000000000..169a12797 --- /dev/null +++ b/cli/cmd/agentplugins/project_kimi_version_lifecycle_test.go @@ -0,0 +1,156 @@ +package main + +import ( + "errors" + "path/filepath" + "reflect" + "strings" + "testing" +) + +func TestProjectKimiEmptyVersionLifecycleRequestsOnlySelectedProbe(t *testing.T) { + for _, saved := range []bool{false, true} { + name := "direct-local" + if saved { + name = "saved-git" + } + t.Run(name, func(t *testing.T) { projectKimiEmptyVersionLifecycle(t, saved) }) + } +} + +func projectKimiEmptyVersionLifecycle(t *testing.T, saved bool) { + t.Helper() + journey, detector := newProjectKimiVersionJourney(t) + userBefore := securityFixtureTree(t, detector.user) + add := []string{"add", journey.transport.repo, "--target", "kimi", "--no-save"} + selector := "project-demo" + if saved { + add = []string{"add", journey.transport.endpoint, "--alias", "docs", "--target", "kimi"} + selector = "docs" + } + for _, project := range []string{journey.a, journey.b} { + before := len(detector.targeted) + journey.run(t, project, add...) + detector.assertCalls(t, before, 1) + } + installation, binding := projectKimiVersionOwned(t, journey, projectJourneySkill, saved) + if !saved { + selector = installation.InstallationID + } + projectJourneyDataMarker(t, journey, journey.a, installation) + bBefore := securityFixtureTree(t, journey.b) + preserved := func() { + t.Helper() + if !reflect.DeepEqual(userBefore, securityFixtureTree(t, detector.user)) || !reflect.DeepEqual(bBefore, securityFixtureTree(t, journey.b)) { + t.Fatal("A version-assisted lifecycle changed original-user or B authority") + } + } + if saved { + before := len(detector.targeted) + state := projectJourneyRead(t, filepath.Join(journey.namespace(journey.a), "state-v2.json")) + journey.run(t, journey.a, "deps", "sync", "--locked", "--yes") + detector.assertCalls(t, before, 0) + if state != projectJourneyRead(t, filepath.Join(journey.namespace(journey.a), "state-v2.json")) { + t.Fatal("unchanged saved Kimi reconciliation rewrote state") + } + } + for _, args := range [][]string{{"list"}, {"info", installation.InstallationID}, {"doctor"}} { + before := len(detector.targeted) + journey.run(t, journey.a, args...) + detector.assertCalls(t, before, 0) + } + if saved { + before := len(detector.targeted) + journey.run(t, journey.a, "deps", "status") + detector.assertCalls(t, before, 0) + } + // Explicit info reconciliation already permits the selected version probe. + before := len(detector.targeted) + journey.run(t, journey.a, "info", installation.InstallationID, "--target", "kimi") + detector.assertCalls(t, before, 1) + for _, args := range [][]string{ + append(append([]string{}, add...), "--dry-run"), + {"update", selector, "--target", "kimi", "--dry-run"}, + {"repair", installation.InstallationID, "--target", "kimi", "--dry-run"}, + } { + before := len(detector.targeted) + snapshot := securityFixtureTree(t, journey.a) + _, err := journey.execute(journey.a, args...) + if err != nil && !strings.Contains(err.Error(), "kimi project components require") { + t.Fatalf("unexpected dry-run failure: %v", err) + } + detector.assertCalls(t, before, 0) + if !reflect.DeepEqual(snapshot, securityFixtureTree(t, journey.a)) { + t.Fatal("dry-run changed project authority") + } + } + // Intact repair exercises public restaging and the missing-version gate; + // the existing Kimi lifecycle retains its separate corrupted-pin repair case. + before = len(detector.targeted) + journey.run(t, journey.a, "repair", installation.InstallationID, "--target", "kimi") + detector.assertCalls(t, before, 1) + projectKimiVersionOwned(t, journey, projectJourneySkill, saved) + preserved() + projectJourneyWrite(t, filepath.Join(journey.transport.repo, "skills", "docs", "SKILL.md"), projectJourneyAdvancedSkill) + if saved { + projectJourneyGit(t, journey.transport.repo, "add", ".") + projectJourneyGit(t, journey.transport.repo, "commit", "-m", "advance Kimi selected-version fixture") + projectJourneyGit(t, journey.transport.repo, "push", "--quiet", journey.transport.remote, "main") + } + before = len(detector.targeted) + journey.run(t, journey.a, "update", selector, "--target", "kimi") + detector.assertCalls(t, before, 1) + updated, current := projectKimiVersionOwned(t, journey, projectJourneyAdvancedSkill, saved) + if updated.Source.TreeDigest == installation.Source.TreeDigest || current.ClientBindingID != binding.ClientBindingID || current.TargetLocator != binding.TargetLocator { + t.Fatal("version-assisted update lost selected source/binding identity") + } + for key, receipt := range installation.DataReceipts { + if updated.DataReceipts[key].Locator != receipt.Locator || projectJourneyRead(t, filepath.Join(receipt.Locator, "keep.txt")) != "retained environment data\n" { + t.Fatal("version-assisted update changed retained data") + } + } + preserved() + before = len(detector.targeted) + journey.run(t, journey.a, "remove", selector, "--target", "kimi") + detector.assertCalls(t, before, 0) + projectJourneyAbsent(t, binding.TargetLocator, filepath.Join(journey.a, ".kimi-code", "skills", "docs")) + preserved() + afterRemoval := securityFixtureTree(t, journey.a) + _, _ = journey.execute(journey.a, "remove", selector, "--target", "kimi") + detector.assertCalls(t, before, 0) + if !reflect.DeepEqual(afterRemoval, securityFixtureTree(t, journey.a)) { + t.Fatal("repeated Kimi removal changed bytes") + } +} + +func TestProjectKimiEmptyVersionProbeErrorAndOtherSelectedFailurePreserveProject(t *testing.T) { + for _, kind := range []string{"probe-error", "other-selected-error"} { + t.Run(kind, func(t *testing.T) { + journey, detector := newProjectKimiVersionJourney(t) + target, calls := "kimi", 1 + if kind == "probe-error" { + detector.probeError = errors.New("selected Kimi fixture probe failed") + } else { + detector.geminiError = errors.New("selected Gemini fixture detection failed") + target, calls = "kimi,gemini", 0 + } + beforeA, beforeB, beforeUser := securityFixtureTree(t, journey.a), securityFixtureTree(t, journey.b), securityFixtureTree(t, detector.user) + _, err := journey.execute(journey.a, "add", journey.transport.repo, "--target", target, "--no-save") + if err == nil { + t.Fatal("failed selected detection unexpectedly installed") + } + detector.assertCalls(t, 0, calls) + if !reflect.DeepEqual(beforeA, securityFixtureTree(t, journey.a)) || !reflect.DeepEqual(beforeB, securityFixtureTree(t, journey.b)) || !reflect.DeepEqual(beforeUser, securityFixtureTree(t, detector.user)) { + t.Fatal("failed selected detection changed native/project authority") + } + }) + } +} + +func TestProjectKimiEmptyVersionUserAndUnselectedOperationsDoNotProbe(t *testing.T) { + journey, detector := newProjectKimiVersionJourney(t) + journey.run(t, "", "add", journey.transport.repo, "--target", "kimi", "--no-save") + detector.assertCalls(t, 0, 0) + journey.run(t, journey.a, "add", journey.transport.repo, "--target", "gemini", "--no-save") + detector.assertCalls(t, 0, 0) +} diff --git a/cli/cmd/agentplugins/project_qoder_e2e_test.go b/cli/cmd/agentplugins/project_qoder_e2e_test.go index 6e8aad245..c4e33b5ae 100644 --- a/cli/cmd/agentplugins/project_qoder_e2e_test.go +++ b/cli/cmd/agentplugins/project_qoder_e2e_test.go @@ -42,7 +42,7 @@ func configureProjectQoder(t *testing.T, app agentpluginscli.App, user string, r app.Installer = engine app.Detector = projectQoderDetector{user} app.Lifecycle.Activator = providers.Activator{Registry: app.ClientRegistry, Runner: runner} - app.Lifecycle.NativeObserver = providers.NativeIdentityObserver{Registry: app.ClientRegistry, Runner: runner} + app.Lifecycle.NativeObserver = providers.NativeIdentityObserver{Stager: app.Lifecycle.Stager, Registry: app.ClientRegistry, Runner: runner} compose := app.ForScope app.ForScope = func(scope domain.InstallScope, root string) (agentpluginscli.App, error) { selected, err := compose(scope, root) @@ -139,3 +139,80 @@ func projectQoderOwned(t *testing.T, j projectJourney, project, expected string) } return installation, b } + +// Exercise the same direct local, explicit-target CLI group route as the native +// cycle. No Qoder process is permitted; repair and retention use production APIs. +func TestProjectQoderDirectGroupRepairAndDefaultRemovalKeepExactAuthority(t *testing.T) { + transport := newProjectJourneyTransport(t, "git") + j := newProjectJourney(t, transport) + user := filepath.Join(j.home, ".qoder") + projectJourneyWrite(t, filepath.Join(user, "plugins", "installed_plugins_v2.json"), "original registry\n") + runner := &projectQoderNoNative{} + j.app = configureProjectQoder(t, j.app, user, runner) + beforeUser := securityFixtureTree(t, user) + for _, project := range []string{j.a, j.b} { + j.run(t, project, "add", transport.repo, "--target", "qoder", "--no-save") + } + installed, binding := projectQoderDirectOwned(t, j, projectJourneySkill) + beforeB := securityFixtureTree(t, j.b) + if len(installed.DataReceipts) != 0 || installed.DataRetained || binding.DataReceiptID != "" { + t.Fatal("skills-only install invented a data allocation") + } + stateBefore := projectJourneyRead(t, filepath.Join(j.a, ".uap", "state-v2.json")) + for _, args := range [][]string{{"add", transport.repo, "--target", "qoder", "--no-save"}, {"update", installed.DeclaredName, "--target", "qoder"}} { + output := j.run(t, j.a, args...) + if !strings.Contains(output, `"mutated":false`) || stateBefore != projectJourneyRead(t, filepath.Join(j.a, ".uap", "state-v2.json")) { + t.Fatal("direct unchanged group changed state", output) + } + } + output := j.run(t, j.a, "repair", installed.InstallationID, "--target", "qoder") + intact, current := projectQoderDirectOwned(t, j, projectJourneySkill) + if !strings.Contains(output, `"mutated":true`) || intact.InstallationID != installed.InstallationID || current.ClientBindingID != binding.ClientBindingID || intact.Source.TreeDigest != installed.Source.TreeDigest { + t.Fatal("explicit direct CLI group repair lost exact restaging authority", output) + } + projectJourneyWrite(t, filepath.Join(transport.repo, "skills", "docs", "SKILL.md"), projectJourneyAdvancedSkill) + j.run(t, j.a, "update", transport.repo, "--target", "qoder") + updated, current := projectQoderDirectOwned(t, j, projectJourneyAdvancedSkill) + if updated.Source.TreeDigest == installed.Source.TreeDigest || current.TargetLocator != binding.TargetLocator { + t.Fatal("same-version direct update lost source or physical authority") + } + // This inert CLI contract owns the complete selected package. The hosted + // cycle separately authorizes each leaf before nonrecursive fault removal. + if err := os.RemoveAll(current.TargetLocator); err != nil { + t.Fatal(err) + } + j.run(t, j.a, "repair", installed.InstallationID, "--target", "qoder") + repaired, _ := projectQoderDirectOwned(t, j, projectJourneyAdvancedSkill) + if repaired.Source.TreeDigest != updated.Source.TreeDigest { + t.Fatal("frozen local repair did not restore its exact recorded digest") + } + j.run(t, j.a, "remove", installed.DeclaredName, "--target", "qoder") + projectJourneyAbsent(t, current.TargetLocator) + state := j.state(t, j.a) + if len(state.Installations) != 1 || !state.Installations[0].DataRetained || len(state.Installations[0].Clients) != 0 || len(state.Installations[0].DataReceipts) != 1 { + t.Fatal("default skills-only removal did not retain its actual owner allocation") + } + if runner.calls != 0 || !reflect.DeepEqual(beforeUser, securityFixtureTree(t, user)) || !reflect.DeepEqual(beforeB, securityFixtureTree(t, j.b)) { + t.Fatal("direct A lifecycle invoked native or changed original user/B authority") + } +} + +func projectQoderDirectOwned(t *testing.T, j projectJourney, expected string) (domain.Installation, domain.ClientBinding) { + t.Helper() + state := j.state(t, j.a) + if len(state.Installations) != 1 || len(state.Installations[0].Clients) != 1 || len(state.EnvironmentReceipts) != 0 { + t.Fatal("direct --no-save route lost exact unsaved state") + } + installation := state.Installations[0] + for _, binding := range installation.Clients { + if binding.ClientID != "qoder" || binding.Scope != "project" || binding.Activation != domain.ActivationPrepared || binding.Verification != domain.VerificationInstalled || binding.NativeProfileRoot != filepath.Join(j.a, ".uap", "managed", "clients", "qoder") || len(binding.NativeObjects) != 1 || binding.NativeObjects[0].Path != binding.TargetLocator { + t.Fatal("direct Prepared receipt ownership differs") + } + if projectJourneyRead(t, filepath.Join(binding.TargetLocator, ".agentplugins-qoder-native", "skills", "docs", "SKILL.md")) != expected { + t.Fatal("direct Qoder native view does not match frozen source") + } + return installation, binding + } + t.Fatal("direct binding missing") + return domain.Installation{}, domain.ClientBinding{} +} diff --git a/cli/cmd/agentplugins/windsurf_user_cache_contract_linux_test.go b/cli/cmd/agentplugins/windsurf_user_cache_contract_linux_test.go new file mode 100644 index 000000000..9f4cef551 --- /dev/null +++ b/cli/cmd/agentplugins/windsurf_user_cache_contract_linux_test.go @@ -0,0 +1,116 @@ +//go:build linux + +package main + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "os" + "path/filepath" + "reflect" + "syscall" + "testing" + + "github.com/777genius/plugin-kit-ai/cli/internal/agentpluginscli" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/adapters/securityscan" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/domain" +) + +const windUserCacheReport = `{"schema_version":1,"tool":{"name":"lintai","version":"0.1.3"},"policy":{"id":"agent-plugin-install","version":2,"presets":["recommended","preview","threat-review","supply-chain","advisory"]},"stats":{"scanned_files":3,"skipped_files":0},"findings":[],"diagnostics":[],"runtime_errors":[]}` + +type windUserCacheScanner struct{ calls int } + +func (s *windUserCacheScanner) Scan(context.Context, string) ([]byte, error) { + s.calls++ + return []byte(windUserCacheReport), nil +} + +// Preserve the real evaluator, cache, policy, lazy source acquirer and scoped +// composer. Only host/service discovery and the scanner response are inert. +func windUserCacheApp(t *testing.T, app agentpluginscli.App, profile string, scanner *windUserCacheScanner) agentpluginscli.App { + t.Helper() + app.Detector = windUserScratchDetector{profile} + app.SecurityIndex, app.DirectoryClient, app.DiscoveryClient = nil, nil, nil + app.DirectoryClientForDryRun, app.CommitDirectoryPreview = nil, nil + evaluator, ok := app.SecurityEvaluator.(securityscan.Evaluator) + if !ok { + t.Fatal("default public security evaluator missing") + } + if _, ok := evaluator.Cache.(securityscan.FileCache); !ok { + t.Fatal("default public assessment file cache missing") + } + if _, ok := app.SourceAcquirer.(lazySourceAcquirer); !ok { + t.Fatal("default lazy source acquirer missing") + } + evaluator.Scanner = scanner + app.SecurityEvaluator = evaluator + compose := app.ForScope + app.ForScope = func(scope domain.InstallScope, root string) (agentpluginscli.App, error) { + selected, err := compose(scope, root) + if err != nil { + return selected, err + } + return windUserCacheApp(t, selected, profile, scanner), nil + } + return app +} + +func TestWindsurfPublicUserAddUsesDefaultSecurityCache(t *testing.T) { + f := newWindUserScratchFixture(t) + marker := filepath.Join(f.state, "security", "lintai", "caller-owned.txt") + projectJourneyWrite(t, marker, "inert original scanner-cache marker; never executed\n") + scanner := &windUserCacheScanner{} + app := windUserCacheApp(t, f.app, f.profile, scanner) + before := securityFixtureTree(t, filepath.Join(f.state, "security")) + raw := windUserScratchExecute(t, app, f.source, f.scratch) + state, err := app.StateStore.Load() + if err != nil || len(state.Installations) != 1 || scanner.calls != 1 { + t.Fatal("actual public evaluator did not scan one exact package", err) + } + i := state.Installations[0] + subject := domain.SecuritySubject{TreeDigest: i.Source.TreeDigest, ManifestDigest: i.Package.ManifestDigest} + requirement := securityscan.DefaultRequirement() + key := securityscan.CacheKey(subject, requirement) + root := filepath.Join(f.state, "security", "assessments") + cache := app.SecurityEvaluator.(securityscan.Evaluator).Cache.(securityscan.FileCache) + assessment, found := cache.Load(key) + if cache.Root != root || !found || assessment.Validate(requirement, subject) != nil || assessment.Evidence != "" { + t.Fatal("real default cache subject/policy differs") + } + reportHash := sha256.Sum256([]byte(windUserCacheReport)) + want := domain.SecurityAssessment{SchemaVersion: 1, Subject: subject, Scanner: requirement.Scanner, Policy: requirement.Policy, Outcome: domain.SecurityNoBlockingFindings, ScannedFiles: 3, ReportDigest: "sha256:" + hex.EncodeToString(reportHash[:])} + expected, err := json.Marshal(want) + if err != nil || !reflect.DeepEqual(assessment, want) || projectJourneyRead(t, filepath.Join(root, key+".json")) != string(expected) { + t.Fatal("real cache bytes differ from exact inert report", err) + } + var public struct { + Data struct { + Security domain.SecurityAssessment `json:"security"` + } `json:"data"` + } + want.Evidence = domain.SecurityEvidenceLocalScan + if json.Unmarshal(raw, &public) != nil || !reflect.DeepEqual(public.Data.Security, want) { + t.Fatal("public User result does not bind the same local scan") + } + entries, err := os.ReadDir(root) + info, statErr := os.Lstat(filepath.Join(root, key+".json")) + if err != nil || statErr != nil || len(entries) != 1 || entries[0].Name() != key+".json" || !info.Mode().IsRegular() || info.Mode() != 0600 { + t.Fatal("finite source-defined assessment cache membership/mode differs") + } + s, ok := info.Sys().(*syscall.Stat_t) + if !ok || s.Uid != uint32(os.Getuid()) || s.Gid != uint32(os.Getgid()) || s.Nlink != 1 { + t.Fatal("assessment cache owner/link differs") + } + after := securityFixtureTree(t, filepath.Join(f.state, "security")) + for name, value := range before { + if after[name] != value { + t.Fatal("default security cache changed original scanner-cache bytes/mode") + } + } + if len(after) != len(before)+2 || projectJourneyRead(t, marker) != "inert original scanner-cache marker; never executed\n" { + t.Fatal("default public source/cache added an unrelated security entry") + } + t.Log("actual default User evaluator: one new assessments directory and one exact source/policy-bound cache file") +} diff --git a/cli/cmd/agentplugins/windsurf_user_scratch_contract_linux_test.go b/cli/cmd/agentplugins/windsurf_user_scratch_contract_linux_test.go new file mode 100644 index 000000000..0ff3e4765 --- /dev/null +++ b/cli/cmd/agentplugins/windsurf_user_scratch_contract_linux_test.go @@ -0,0 +1,151 @@ +//go:build linux + +package main + +import ( + "bytes" + "context" + "encoding/json" + "os" + "path/filepath" + "reflect" + "strings" + "syscall" + "testing" + "time" + + "github.com/777genius/plugin-kit-ai/cli/internal/agentpluginscli" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/adapters/sourceacquisition" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/adapters/specregistry" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/domain" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/ports" +) + +type windUserScratchDetector struct{ profile string } + +func (d windUserScratchDetector) Detect(context.Context) ([]domain.DetectedClient, error) { + return []domain.DetectedClient{{ClientID: domain.ClientWindsurf, ConfigRoot: d.profile, Status: domain.DetectionDetected}}, nil +} + +func windUserScratchApp(app agentpluginscli.App, profile, state string) agentpluginscli.App { + app.Detector = windUserScratchDetector{profile} + app.SecurityIndex, app.DirectoryClient, app.DiscoveryClient = nil, nil, nil + app.DirectoryClientForDryRun, app.CommitDirectoryPreview = nil, nil + app.SecurityEvaluator = projectJourneySecurity{} + app.SecurityEvaluatorForDryRun = func(string) ports.PackageSecurityEvaluator { return projectJourneySecurity{} } + app.SourceAcquirer = sourceacquisition.Acquirer{TempRoot: state} + compose := app.ForScope + app.ForScope = func(scope domain.InstallScope, root string) (agentpluginscli.App, error) { + selected, err := compose(scope, root) + if err != nil { + return selected, err + } + return windUserScratchApp(selected, profile, state), nil + } + return app +} + +type windUserScratchFixture struct { + app agentpluginscli.App + state, scratch, source, profile string +} + +func newWindUserScratchFixture(t *testing.T) windUserScratchFixture { + t.Helper() + root := projectJourneyTemp(t) + home, state, scratch, source := filepath.Join(root, "home"), filepath.Join(root, "installer-state"), filepath.Join(root, "tmp"), filepath.Join(root, "source") + profile := filepath.Join(home, ".codeium", "windsurf") + for _, path := range []string{state, scratch} { + if err := os.Mkdir(path, 0700); err != nil { + t.Fatal(err) + } + } + for _, name := range []string{"TMPDIR", "TEMP", "TMP"} { + t.Setenv(name, scratch) + } + config := filepath.Join(profile, "mcp_config.json") + projectJourneyWrite(t, config, `{"mcpServers":{"foreign-user":{"serverUrl":"http://127.0.0.1:9/foreign-user","disabled":true}},"foreignPreference":"keep"}`) + lock := config + ".agentplugins.lock" + projectJourneyWrite(t, lock, "") + foreignSkill := filepath.Join(profile, "skills", "foreign-user", "SKILL.md") + projectJourneyWrite(t, foreignSkill, "foreign User skill; never executed\n") + projectJourneyWrite(t, filepath.Join(source, "plugin.json"), `{"$schema":"https://agent-plugins.org/schemas/1.0.0/plugin.schema.json","name":"uap-windsurf-component","version":"1.0.0"}`) + projectJourneyWrite(t, filepath.Join(source, "skills", "uap-windsurf-component", "SKILL.md"), "---\nname: uap-windsurf-component\ndescription: Inert scratch reproduction\n---\nNever executed\n") + projectJourneyWrite(t, filepath.Join(source, "mcp.json"), `{"$schema":"https://agent-plugins.org/schemas/1.0.0/mcp.schema.json","mcpServers":{"uap-windsurf-component":{"type":"streamable-http","url":"http://127.0.0.1:9/no-execution"}}}`) + registry, err := specregistry.New() + if err != nil { + t.Fatal(err) + } + app, err := newAgentpluginsCLIApp(home, state, nil, nil, nil, registry) + if err != nil { + t.Fatal(err) + } + return windUserScratchFixture{app, state, scratch, source, profile} +} + +func TestWindsurfPublicUserAddUsesDefaultSnapshotScratch(t *testing.T) { + f := newWindUserScratchFixture(t) + app := windUserScratchApp(f.app, f.profile, f.state) + windUserScratchExecute(t, app, f.source, f.scratch) + config := filepath.Join(f.profile, "mcp_config.json") + foreignSkill := filepath.Join(f.profile, "skills", "foreign-user", "SKILL.md") + var document struct { + Servers map[string]json.RawMessage `json:"mcpServers"` + Preference string `json:"foreignPreference"` + } + raw, err := os.ReadFile(config) + if err != nil || json.Unmarshal(raw, &document) != nil || len(document.Servers) != 2 || document.Preference != "keep" { + t.Fatal("ordinary User add native config/foreign preservation", err) + } + var foreign map[string]any + if json.Unmarshal(document.Servers["foreign-user"], &foreign) != nil || !reflect.DeepEqual(foreign, map[string]any{"serverUrl": "http://127.0.0.1:9/foreign-user", "disabled": true}) || !bytes.Contains(document.Servers["uap-windsurf-component"], []byte("http://127.0.0.1:9/no-execution")) { + t.Fatal("selected native server or original foreign server differs") + } + if projectJourneyRead(t, foreignSkill) != "foreign User skill; never executed\n" { + t.Fatal("foreign skill changed") + } +} + +func windUserScratchExecute(t *testing.T, app agentpluginscli.App, source, scratch string) []byte { + t.Helper() + lock := filepath.Join(app.UserHome, ".codeium", "windsurf", "mcp_config.json.agentplugins.lock") + before, err := os.Lstat(scratch) + if err != nil { + t.Fatal(err) + } + lockBefore, err := os.Lstat(lock) + if err != nil { + t.Fatal(err) + } + var output, stderr bytes.Buffer + app.Input, app.Output, app.ErrorOutput, app.Terminal = strings.NewReader(""), &output, &stderr, false + command := agentpluginscli.NewRoot(app) + command.SetArgs([]string{"add", source, "--no-save", "--scope", "user", "--target", "windsurf", "--format", "json"}) + time.Sleep(20 * time.Millisecond) + if err := command.Execute(); err != nil { + t.Fatalf("ordinary User add: %v\n%s\n%s", err, output.String(), stderr.String()) + } + var result map[string]any + if json.Unmarshal(output.Bytes(), &result) != nil || result["command"] != "add" || result["result"] != "success" { + t.Fatal("public add result differs", output.String()) + } + after, err := os.Lstat(scratch) + if err != nil { + t.Fatal(err) + } + entries, err := os.ReadDir(scratch) + if err != nil || len(entries) != 0 || !os.SameFile(before, after) || before.Mode() != after.Mode() || before.Size() != after.Size() { + t.Fatal("ordinary User add scratch authority/membership differs", err) + } + oldStat, oldOK := before.Sys().(*syscall.Stat_t) + newStat, newOK := after.Sys().(*syscall.Stat_t) + if !oldOK || !newOK || oldStat.Uid != newStat.Uid || oldStat.Gid != newStat.Gid || (oldStat.Mtim == newStat.Mtim && oldStat.Ctim == newStat.Ctim) { + t.Fatal("actual User scratch timestamp-only effect differs") + } + lockAfter, err := os.Lstat(lock) + if err != nil || !os.SameFile(lockBefore, lockAfter) || lockAfter.Mode() != 0600 || lockAfter.Size() != 0 { + t.Fatal("existing native lock identity changed", err) + } + t.Logf("actual User scratch: size_equal=%t modified_equal=%t changed_equal=%t", before.Size() == after.Size(), oldStat.Mtim == newStat.Mtim, oldStat.Ctim == newStat.Ctim) + return append([]byte{}, output.Bytes()...) +} diff --git a/cli/internal/agentpluginscli/add.go b/cli/internal/agentpluginscli/add.go index 57f42ad26..ddce9ad14 100644 --- a/cli/internal/agentpluginscli/add.go +++ b/cli/internal/agentpluginscli/add.go @@ -112,7 +112,7 @@ func executePromptedAdd(cmd *cobra.Command, app App, opts *options, source strin if err != nil { return fmt.Errorf("detect selected AI clients: %w", err) } - _, detected, err := preflightSelectedTargets(cmd.Context(), app, selection, detectedClients, false) + _, detected, err := preflightProjectLifecycleTargets(cmd.Context(), app, opts, selection, detectedClients, false) if err != nil { return err } diff --git a/cli/internal/agentpluginscli/deps_sync.go b/cli/internal/agentpluginscli/deps_sync.go index 5e57c41d0..c5fc2726e 100644 --- a/cli/internal/agentpluginscli/deps_sync.go +++ b/cli/internal/agentpluginscli/deps_sync.go @@ -123,6 +123,9 @@ func loadStoredDependency(ctx context.Context, app App, pkg environmentstore.Pac func preflightDependencyActions(cmd *cobra.Command, app App, opts *options, actions []dependencyAction, detected map[domain.ClientID]domain.DetectedClient, consent ...map[string]bool) ([]dependencyAction, error) { adapter := &dependencyInstaller{app: app, opts: opts, detected: detected, cmd: cmd} + if err := adapter.preflightProjectVersions(cmd.Context(), actions); err != nil { + return nil, err + } if len(consent) > 0 { adapter.consent = consent[0] } @@ -177,6 +180,27 @@ func preflightDependencyAdapter(ctx context.Context, adapter *dependencyInstalle return actions, nil } +func (adapter *dependencyInstaller) preflightProjectVersions(ctx context.Context, actions []dependencyAction) error { + if adapter.app.scope() != domain.ScopeProject || adapter.opts.dryRun { + return nil + } + var targets []domain.ClientID + for _, action := range actions { + if action.Action == environment.ActionUnchanged { + continue + } + id := domain.ClientID(action.ClientID) + client, ok := adapter.detected[id] + if !ok || (action.Action != environment.ActionRemove && (client.Status != domain.DetectionDetected || client.DetectionError != nil)) { + return fmt.Errorf("target %s is not detected; nothing was changed", action.ClientID) + } + if action.Action == environment.ActionInstall || action.Action == environment.ActionUpdate || action.Action == "repair" { + targets = append(targets, id) + } + } + return ensureSelectedProjectVersions(ctx, adapter.app, adapter.opts, targets, adapter.detected) +} + func (adapter *dependencyInstaller) recordDependencyComponents(action dependencyAction, plan installer.Plan) { opts := adapter.opts if opts.dependencyComponents == nil { diff --git a/cli/internal/agentpluginscli/prepare.go b/cli/internal/agentpluginscli/prepare.go index f81fc5dc1..3e848bf64 100644 --- a/cli/internal/agentpluginscli/prepare.go +++ b/cli/internal/agentpluginscli/prepare.go @@ -181,7 +181,7 @@ func assignLoadedGuidedIntent(opts *options, loaded loadedPackage, target domain } func preflightAddTargets(ctx context.Context, app App, opts *options, source string, targets []domain.ClientID, clients []domain.DetectedClient) ([]domain.DetectedClient, map[domain.ClientID]domain.DetectedClient, error) { - return preflightSelectedTargets(ctx, app, targets, clients, !opts.dryRun && isDirectorySelector(source), opts.installIntents) + return preflightProjectLifecycleTargets(ctx, app, opts, targets, clients, !opts.dryRun && isDirectorySelector(source), opts.installIntents) } func automaticInstallTargets(targets []domain.ClientID, intents map[domain.ClientID]domain.InstallIntent) []domain.ClientID { diff --git a/cli/internal/agentpluginscli/project_grok_cycle_contract_test.go b/cli/internal/agentpluginscli/project_grok_cycle_contract_test.go new file mode 100644 index 000000000..67fbd5224 --- /dev/null +++ b/cli/internal/agentpluginscli/project_grok_cycle_contract_test.go @@ -0,0 +1,187 @@ +//go:build linux + +package agentpluginscli + +import ( + "context" + "encoding/json" + "fmt" + "os" + "path/filepath" + "reflect" + "strings" + "testing" + + "github.com/777genius/plugin-kit-ai/install/integrationctl/adapters/dirswap" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/adapters/processlock" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/adapters/statev2" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/domain" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/installer" + clientplanner "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/planner" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/plannertest" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/providers" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/providerstest" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/transaction" + legacyports "github.com/777genius/plugin-kit-ai/install/integrationctl/ports" +) + +type cycleGrokCLIRunner struct{ project, executable string } + +func (r cycleGrokCLIRunner) Run(_ context.Context, command legacyports.Command) (legacyports.CommandResult, error) { + if command.Dir != r.project || !reflect.DeepEqual(command.Argv, []string{r.executable, "inspect", "--json"}) { + return legacyports.CommandResult{}, fmt.Errorf("unregistered inert Grok CLI command") + } + plugins := []any{} + root := filepath.Join(r.project, ".grok", "plugins") + entries, err := os.ReadDir(root) + if err != nil && !os.IsNotExist(err) { + return legacyports.CommandResult{}, err + } + for _, entry := range entries { + path := filepath.Join(root, entry.Name()) + body, err := os.ReadFile(filepath.Join(path, ".grok-plugin", "plugin.json")) + if err != nil { + return legacyports.CommandResult{}, err + } + var manifest map[string]any + if err := json.Unmarshal(body, &manifest); err != nil { + return legacyports.CommandResult{}, err + } + plugins = append(plugins, map[string]any{"name": manifest["name"], "scope": "project", "path": path, "enabled": true}) + } + body, err := json.Marshal(map[string]any{"grokVersion": "1.0.70", "cwd": r.project, "projectRoot": r.project + "/", "projectTrusted": true, "plugins": plugins, "skills": []any{}}) + return legacyports.CommandResult{Stdout: body}, err +} + +// Exercise public Cobra routing and the real grouped lifecycle with an inert +// in-memory inspector. No vendor executable is run or qualified. +func TestProjectGrokPublicGroupedRepairRestagesIntactAndMissingPackage(t *testing.T) { + client := fixtureClient(t, domain.ClientGrok) + f := newCLIFixture(t, []domain.DetectedClient{client}) + project := filepath.Join(f.root, "project") + for _, path := range []string{project, client.ConfigRoot} { + if err := os.MkdirAll(path, 0700); err != nil { + t.Fatal(err) + } + } + client.ExecutablePath, client.Version = filepath.Join(f.root, "inert-grok"), "1.0.70" + if err := os.WriteFile(client.ExecutablePath, []byte("inert bytes; never executed\n"), 0700); err != nil { + t.Fatal(err) + } + f.app.Detector = staticDetector{clients: []domain.DetectedClient{client}} + stateRoot := filepath.Join(project, ".uap") + f.store = statev2.Store{Path: filepath.Join(stateRoot, "state-v2.json"), ProjectRoot: project} + f.app.Scope, f.app.ProjectRoot, f.app.ManagedRoot, f.app.StateStore = domain.ScopeProject, project, filepath.Join(stateRoot, "managed"), f.store + f.app.EnvironmentLockPath = filepath.Join(stateRoot, "environment.lock") + planner := plannertest.NewPlanner(clientplanner.Planner{ProjectRoot: project, ManagedRoot: f.app.ManagedRoot}) + f.app.Planner, f.app.Targets = planner, planner + runner := cycleGrokCLIRunner{project, client.ExecutablePath} + f.app.Lifecycle.ProjectRoot, f.app.Lifecycle.StateStore = project, f.store + f.app.Lifecycle.Planner, f.app.Lifecycle.Targets = planner, planner + f.app.Lifecycle.Activator = providerstest.NewActivator(providers.Activator{Runner: runner}) + f.app.Lifecycle.NativeObserver = providerstest.NewObserver(providers.NativeIdentityObserver{Runner: runner, Stager: f.app.Lifecycle.Stager}) + f.app.Lifecycle.Lock = processlock.Lock{Path: filepath.Join(stateRoot, "mutation.lock")} + f.app.Lifecycle.Kernel = transaction.Kernel{StateStore: f.store, Directory: dirswap.Manager{JournalDir: filepath.Join(stateRoot, "operations")}} + f.app.Lifecycle.PluginData = providers.PluginDataManager{Base: filepath.Join(stateRoot, "plugin-data")} + var err error + f.app.Installer, err = installer.New(installer.Config{ProjectRoot: project, StateRoot: stateRoot, Registry: f.app.ClientRegistry, Runner: runner, HelperExecutable: client.ExecutablePath, EnableNativeObserver: true, TrustedLocalPackages: true}) + if err != nil { + t.Fatal(err) + } + f.app.Lifecycle.CheckNamespace = f.app.Installer.CheckProjectNamespace + source := writeCLIPlugin(t) + skill := []byte("---\nname: guide\ndescription: Inert public repair\n---\nRecorded source.\n") + if err := os.MkdirAll(filepath.Join(source, "skills", "guide"), 0700); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(source, "skills", "guide", "SKILL.md"), skill, 0600); err != nil { + t.Fatal(err) + } + run := func(verb, selector string, mutated bool) { + t.Helper() + args := []string{verb, selector, "--scope", "project", "--project-root", project, "--target", "grok", "--format", "json"} + if verb == "add" { + args = append(args, "--no-save") + } + stdout, stderr, err := f.execute(false, args...) + if err != nil { + t.Fatalf("actual public %s: %v\n%s\n%s", verb, err, stdout, stderr) + } + var result map[string]any + if err := json.Unmarshal([]byte(stdout), &result); err != nil { + t.Fatal(err) + } + data := result["data"].(map[string]any) + output := data + if verb == "add" && !mutated { + if _, exists := data["targets"]; exists || data["operation_id"] != nil { + t.Fatal("actual repeat add invented a batch/group", stdout) + } + } else { + if data["batch"] != true { + t.Fatal("actual grouped lifecycle lost batch output", stdout) + } + output = data["targets"].([]any)[0].(map[string]any)["output"].(map[string]any) + } + expectedSource := "direct local source" + if verb == "repair" || verb == "remove" { + expectedSource = "local" + } + if output["source"] != expectedSource { + t.Fatal("actual public source differs", verb, stdout) + } + out := output["result"].(map[string]any) + if out["mutated"] != mutated { + t.Fatalf("actual public %s mutated=%v want%t", verb, out["mutated"], mutated) + } + } + run("add", source, true) + state, err := f.store.Load() + if err != nil || len(state.Installations) != 1 { + t.Fatal(err) + } + i := state.Installations[0] + beforeNoop, err := os.ReadFile(f.store.Path) + if err != nil { + t.Fatal(err) + } + run("add", source, false) + run("update", i.DeclaredName, false) + afterNoop, err := os.ReadFile(f.store.Path) + if err != nil || string(beforeNoop) != string(afterNoop) { + t.Fatal("actual public no-op changed installed state", err) + } + var binding domain.ClientBinding + for _, b := range i.Clients { + binding = b + } + run("repair", i.InstallationID, true) + path := filepath.Join(binding.TargetLocator, "skills", "guide", "SKILL.md") + if err := os.Remove(path); err != nil { + t.Fatal(err) + } + before, err := os.ReadFile(f.store.Path) + if err != nil { + t.Fatal(err) + } + files := preparedClaudeCLIFiles(t, binding.TargetLocator) + _, _, err = f.execute(false, "repair", i.InstallationID, "--scope", "project", "--project-root", project, "--target", "grok", "--format", "json") + after, readErr := os.ReadFile(f.store.Path) + if err == nil || !strings.Contains(err.Error(), "native identity ownership is indeterminate") || readErr != nil || string(before) != string(after) || !reflect.DeepEqual(files, preparedClaudeCLIFiles(t, binding.TargetLocator)) { + t.Fatal("public grouped repair adopted or changed partially missing package", err, readErr) + } + if len(files) != 2 || files[filepath.Join(binding.TargetLocator, "plugin.json")] == "" || files[filepath.Join(binding.TargetLocator, ".grok-plugin", "plugin.json")] == "" { + t.Fatal("inert owned package membership changed before exact absence fault") + } + for _, relative := range []string{"plugin.json", ".grok-plugin/plugin.json", "skills/guide", "skills", ".grok-plugin", "."} { + if err := os.Remove(filepath.Join(binding.TargetLocator, filepath.FromSlash(relative))); err != nil { + t.Fatal("exact nonrecursive owned package absence fault", err) + } + } + run("repair", i.InstallationID, true) + restored, err := os.ReadFile(path) + if err != nil || string(restored) != string(skill) { + t.Fatal("public grouped repair did not restore exact missing leaf", err) + } + run("remove", i.DeclaredName, true) +} diff --git a/cli/internal/agentpluginscli/project_version_preflight.go b/cli/internal/agentpluginscli/project_version_preflight.go new file mode 100644 index 000000000..f09409796 --- /dev/null +++ b/cli/internal/agentpluginscli/project_version_preflight.go @@ -0,0 +1,104 @@ +package agentpluginscli + +import ( + "context" + "fmt" + "strings" + + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/clients" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/domain" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/ports" +) + +// Project adapters can require a current version even for a local package. +// Validate the complete selection before executing the one missing version +// probe, and retain the original discovery facts for every client. +func preflightProjectLifecycleTargets(ctx context.Context, app App, opts *options, targets []domain.ClientID, observedClients []domain.DetectedClient, probeVersion bool, intents ...map[domain.ClientID]domain.InstallIntent) ([]domain.DetectedClient, map[domain.ClientID]domain.DetectedClient, error) { + selected, detected, err := preflightSelectedTargets(ctx, app, targets, observedClients, probeVersion, intents...) + if err != nil { + return nil, nil, err + } + if err := ensureSelectedProjectVersions(ctx, app, opts, targets, detected); err != nil { + return nil, nil, err + } + for i := range selected { + selected[i] = detected[selected[i].ClientID] + } + return selected, detected, nil +} + +func ensureSelectedProjectVersions(ctx context.Context, app App, opts *options, targets []domain.ClientID, detected map[domain.ClientID]domain.DetectedClient) error { + if app.scope() != domain.ScopeProject || opts.dryRun { + return nil + } + if app.ClientRegistry == nil { + return clients.ErrRegistryRequired + } + requested := missingProjectVersionTargets(app.ClientRegistry, targets, detected) + if len(requested) == 0 { + return nil + } + targeted, ok := app.Detector.(ports.TargetedVersionProbingClientDetector) + if !ok { + // Keep the existing adapter version precondition closed. A detector + // without targeted probing must never execute unrelated clients. + return nil + } + probed, err := targeted.DetectTargetsWithVersionProbe(ctx, requested) + if err != nil { + return fmt.Errorf("targets %v version detection failed; no target was changed: %w", requested, err) + } + versions := make(map[domain.ClientID]string, len(requested)) + for _, id := range requested { + version, err := selectedProjectVersion(detected[id], probed) + if err != nil { + return err + } + versions[id] = version + } + for _, id := range requested { + client := detected[id] + client.Version = versions[id] + detected[id] = client + } + return nil +} + +func missingProjectVersionTargets(registry *clients.Registry, targets []domain.ClientID, detected map[domain.ClientID]domain.DetectedClient) []domain.ClientID { + var requested []domain.ClientID + seen := map[domain.ClientID]bool{} + for _, id := range targets { + client, ok := detected[id] + if seen[id] || !ok || client.Status != domain.DetectionDetected || client.DetectionError != nil || client.ExecutablePath == "" || strings.TrimSpace(client.Version) != "" { + continue + } + requirement, ok := clients.As[clients.ProjectVersionRequirement](registry, id) + if !ok || !requirement.RequiresProjectVersion(client) { + continue + } + requested = append(requested, id) + seen[id] = true + } + return requested +} + +func selectedProjectVersion(original domain.DetectedClient, probed []domain.DetectedClient) (string, error) { + var client domain.DetectedClient + matches := 0 + for _, candidate := range probed { + if candidate.ClientID == original.ClientID { + client = candidate + matches++ + } + } + if matches != 1 { + return "", fmt.Errorf("target %q version detection returned %d matching clients; no target was changed", original.ClientID, matches) + } + if client.Status != domain.DetectionDetected || client.DetectionError != nil || strings.TrimSpace(client.Version) == "" { + return "", fmt.Errorf("target %q version detection did not return a successful version; no target was changed", original.ClientID) + } + if client.ExecutablePath != original.ExecutablePath || client.ConfigRoot != original.ConfigRoot || client.ProfileNamespace != original.ProfileNamespace || !domain.SameProfileAuthority(client.ProfileAuthority, original.ProfileAuthority) { + return "", fmt.Errorf("target %q identity changed during version detection; no target was changed", original.ClientID) + } + return client.Version, nil +} diff --git a/cli/internal/agentpluginscli/project_version_preflight_test.go b/cli/internal/agentpluginscli/project_version_preflight_test.go new file mode 100644 index 000000000..626507fcb --- /dev/null +++ b/cli/internal/agentpluginscli/project_version_preflight_test.go @@ -0,0 +1,269 @@ +package agentpluginscli + +import ( + "context" + "errors" + "os" + "path/filepath" + "reflect" + "testing" + + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/adapters/statev2" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/clients" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/clients/kimi" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/clients/windsurf" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/domain" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/environment" +) + +func projectVersionRegistry(t *testing.T) *clients.Registry { + t.Helper() + registry, err := clients.NewRegistry(kimi.New(), windsurf.New()) + if err != nil { + t.Fatal(err) + } + return registry +} + +func TestProjectLifecycleVersionProbeRequiresInjectedRegistry(t *testing.T) { + client := projectVersionClient() + detector := &projectVersionDetector{err: errors.New("must not execute")} + detected := map[domain.ClientID]domain.DetectedClient{client.ClientID: client} + err := ensureSelectedProjectVersions(context.Background(), App{Scope: domain.ScopeProject, Detector: detector}, &options{}, []domain.ClientID{client.ClientID}, detected) + if !errors.Is(err, clients.ErrRegistryRequired) || len(detector.targets) != 0 || detector.broadCalls != 0 || !reflect.DeepEqual(detected[client.ClientID], client) { + t.Fatalf("missing injected registry did not fail closed: %v", err) + } +} + +type projectVersionPlainAdapter struct{ id domain.ClientID } + +func (adapter projectVersionPlainAdapter) ID() domain.ClientID { return adapter.id } + +func TestProjectLifecycleVersionProbeRequiresAdapterCapability(t *testing.T) { + client := projectVersionClient() + registry, err := clients.NewRegistry(projectVersionPlainAdapter{id: client.ClientID}) + if err != nil { + t.Fatal(err) + } + detector := &projectVersionDetector{err: errors.New("must not execute")} + detected := map[domain.ClientID]domain.DetectedClient{client.ClientID: client} + if err := ensureSelectedProjectVersions(context.Background(), App{Scope: domain.ScopeProject, Detector: detector, ClientRegistry: registry}, &options{}, []domain.ClientID{client.ClientID}, detected); err != nil || len(detector.targets) != 0 || detector.broadCalls != 0 || !reflect.DeepEqual(detected[client.ClientID], client) { + t.Fatalf("absent adapter capability executed or changed discovery: %v", err) + } +} + +type projectVersionDetector struct { + clients, probed []domain.DetectedClient + targets [][]domain.ClientID + err error + broadCalls int +} + +func (detector *projectVersionDetector) Detect(context.Context) ([]domain.DetectedClient, error) { + return append([]domain.DetectedClient(nil), detector.clients...), nil +} + +func (detector *projectVersionDetector) DetectWithVersionProbe(context.Context) ([]domain.DetectedClient, error) { + detector.broadCalls++ + return nil, errors.New("broad version probes must not execute") +} + +func (detector *projectVersionDetector) DetectTargetsWithVersionProbe(_ context.Context, targets []domain.ClientID) ([]domain.DetectedClient, error) { + detector.targets = append(detector.targets, append([]domain.ClientID(nil), targets...)) + return append([]domain.DetectedClient(nil), detector.probed...), detector.err +} + +// Native paths must be absolute on Windows as well as Unix. No fixture +// executable is created or launched by these inert version-probe tests. +func projectVersionFixturePath(elements ...string) string { + return filepath.Join(append([]string{os.TempDir(), "uap-project-version-fixture"}, elements...)...) +} + +func projectVersionClient() domain.DetectedClient { + return domain.DetectedClient{ + ClientID: domain.ClientKimi, DisplayName: "original Kimi", Status: domain.DetectionDetected, + ExecutablePath: projectVersionFixturePath("bin", "kimi"), ConfigRoot: projectVersionFixturePath("user", ".kimi"), ProfileNamespace: "original-user", + Surfaces: []domain.ClientSurface{{ID: "cli", Detected: true, Evidence: "original discovery"}}, + } +} + +func TestProjectLifecycleVersionProbePreservesDiscovery(t *testing.T) { + original := projectVersionClient() + other := domain.DetectedClient{ClientID: domain.ClientGemini, Status: domain.DetectionDetected, Version: "ambient"} + probed := original + probed.Version, probed.DisplayName, probed.Surfaces = "2.3.1", "new unrelated display fact", nil + detector := &projectVersionDetector{clients: []domain.DetectedClient{original, other}, probed: []domain.DetectedClient{ + probed, {ClientID: domain.ClientGemini, Version: "must not replace ambient discovery"}, + }} + selected, detected, err := preflightProjectLifecycleTargets(context.Background(), App{ClientRegistry: projectVersionRegistry(t), Scope: domain.ScopeProject, Detector: detector}, &options{}, []domain.ClientID{domain.ClientKimi}, nil, false) + if err != nil { + t.Fatal(err) + } + want := original + want.Version = "2.3.1" + if !reflect.DeepEqual(selected, []domain.DetectedClient{want}) || !reflect.DeepEqual(detected[domain.ClientKimi], want) || !reflect.DeepEqual(detected[domain.ClientGemini], other) { + t.Fatalf("version probe replaced discovery facts: selected=%+v detected=%+v", selected, detected) + } + if !reflect.DeepEqual(detector.clients[0], original) { + t.Fatal("version probe mutated the original discovery slice") + } + if !reflect.DeepEqual(detector.targets, [][]domain.ClientID{{domain.ClientKimi}}) || detector.broadCalls != 0 { + t.Fatalf("unexpected probes: targeted=%v broad=%d", detector.targets, detector.broadCalls) + } +} + +func TestProjectLifecycleVersionProbeRejectsUnboundResults(t *testing.T) { + tests := []struct { + name string + change func(*projectVersionDetector) + }{ + {"missing", func(d *projectVersionDetector) { d.probed = nil }}, + {"duplicate", func(d *projectVersionDetector) { d.probed = append(d.probed, d.probed[0]) }}, + {"empty version", func(d *projectVersionDetector) { d.probed[0].Version = "" }}, + {"blank version", func(d *projectVersionDetector) { d.probed[0].Version = " \t" }}, + {"not detected", func(d *projectVersionDetector) { d.probed[0].Status = domain.DetectionNotDetected }}, + {"detection error", func(d *projectVersionDetector) { d.probed[0].DetectionError = errors.New("failed detection") }}, + {"executable changed", func(d *projectVersionDetector) { d.probed[0].ExecutablePath += "-other" }}, + {"config root changed", func(d *projectVersionDetector) { d.probed[0].ConfigRoot += "-other" }}, + {"profile namespace changed", func(d *projectVersionDetector) { d.probed[0].ProfileNamespace += "-other" }}, + {"profile authority changed", func(d *projectVersionDetector) { d.probed[0].ProfileAuthority = &domain.ProfileAuthority{} }}, + {"probe error", func(d *projectVersionDetector) { d.err = errors.New("version command failed") }}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + original := projectVersionClient() + probed := original + probed.Version = "2.3.1" + detector := &projectVersionDetector{probed: []domain.DetectedClient{probed}} + test.change(detector) + detected := map[domain.ClientID]domain.DetectedClient{domain.ClientKimi: original} + err := ensureSelectedProjectVersions(context.Background(), App{ClientRegistry: projectVersionRegistry(t), Scope: domain.ScopeProject, Detector: detector}, &options{}, []domain.ClientID{domain.ClientKimi}, detected) + if err == nil { + t.Fatal("unbound or unsuccessful version observation was accepted") + } + if !reflect.DeepEqual(detected, map[domain.ClientID]domain.DetectedClient{domain.ClientKimi: original}) { + t.Fatal("failed version observation changed discovery facts") + } + if !reflect.DeepEqual(detector.targets, [][]domain.ClientID{{domain.ClientKimi}}) || detector.broadCalls != 0 { + t.Fatalf("unexpected probes: targeted=%v broad=%d", detector.targets, detector.broadCalls) + } + }) + } +} + +func TestProjectLifecycleVersionProbeEligibility(t *testing.T) { + tests := []struct { + name string + scope domain.InstallScope + dryRun bool + target domain.ClientID + change func(*domain.DetectedClient) + }{ + {"user scope", domain.ScopeUser, false, domain.ClientKimi, nil}, + {"dry run", domain.ScopeProject, true, domain.ClientKimi, nil}, + {"unselected", domain.ScopeProject, false, domain.ClientGemini, nil}, + {"known version", domain.ScopeProject, false, domain.ClientKimi, func(c *domain.DetectedClient) { c.Version = "2.3.1" }}, + {"no executable", domain.ScopeProject, false, domain.ClientKimi, func(c *domain.DetectedClient) { c.ExecutablePath = "" }}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + client := projectVersionClient() + if test.change != nil { + test.change(&client) + } + detector := &projectVersionDetector{err: errors.New("must not probe")} + detected := map[domain.ClientID]domain.DetectedClient{domain.ClientKimi: client} + if err := ensureSelectedProjectVersions(context.Background(), App{ClientRegistry: projectVersionRegistry(t), Scope: test.scope, Detector: detector}, &options{dryRun: test.dryRun}, []domain.ClientID{test.target}, detected); err != nil { + t.Fatal(err) + } + if len(detector.targets) != 0 || detector.broadCalls != 0 || !reflect.DeepEqual(detected[domain.ClientKimi], client) { + t.Fatalf("ineligible operation probed or changed discovery: %+v", detector) + } + }) + } +} + +type projectVersionBroadOnlyDetector struct { + staticDetector + calls int +} + +func (detector *projectVersionBroadOnlyDetector) DetectWithVersionProbe(context.Context) ([]domain.DetectedClient, error) { + detector.calls++ + return nil, errors.New("must not fall back to broad version detection") +} + +func TestProjectLifecycleVersionProbeRequiresTargetedCapability(t *testing.T) { + client := projectVersionClient() + detector := &projectVersionBroadOnlyDetector{staticDetector: staticDetector{clients: []domain.DetectedClient{client}}} + selected, _, err := preflightProjectLifecycleTargets(context.Background(), App{ClientRegistry: projectVersionRegistry(t), Scope: domain.ScopeProject, Detector: detector}, &options{}, []domain.ClientID{domain.ClientKimi}, nil, false) + if err != nil { + t.Fatal(err) + } + if detector.calls != 0 || len(selected) != 1 || selected[0].Version != "" { + t.Fatal("missing targeted capability executed a broad probe or invented a version") + } +} + +func TestProjectDependencyVersionsValidateCompleteActionSet(t *testing.T) { + tests := []struct { + name string + actions []dependencyAction + wantProbe bool + wantError bool + }{ + {"install", []dependencyAction{{ClientID: "kimi", Action: environment.ActionInstall}}, true, false}, + {"update", []dependencyAction{{ClientID: "kimi", Action: environment.ActionUpdate}}, true, false}, + {"repair", []dependencyAction{{ClientID: "kimi", Action: "repair"}}, true, false}, + {"remove", []dependencyAction{{ClientID: "kimi", Action: environment.ActionRemove}}, false, false}, + {"unchanged", []dependencyAction{{ClientID: "kimi", Action: environment.ActionUnchanged}}, false, false}, + {"invalid later target", []dependencyAction{{ClientID: "kimi", Action: environment.ActionInstall}, {ClientID: "gemini", Action: environment.ActionInstall}}, false, true}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + client := projectVersionClient() + probed := client + probed.Version = "2.3.1" + detector := &projectVersionDetector{probed: []domain.DetectedClient{probed}} + adapter := &dependencyInstaller{app: App{ClientRegistry: projectVersionRegistry(t), Scope: domain.ScopeProject, Detector: detector}, opts: &options{}, detected: map[domain.ClientID]domain.DetectedClient{ + domain.ClientKimi: client, domain.ClientGemini: {ClientID: domain.ClientGemini, Status: domain.DetectionNotDetected}, + }} + err := adapter.preflightProjectVersions(context.Background(), test.actions) + if (err != nil) != test.wantError { + t.Fatalf("error=%v wantError=%v", err, test.wantError) + } + if (len(detector.targets) == 1) != test.wantProbe || detector.broadCalls != 0 { + t.Fatalf("probes=%v broad=%d wantProbe=%v", detector.targets, detector.broadCalls, test.wantProbe) + } + if test.wantProbe && (adapter.detected[domain.ClientKimi].Version != "2.3.1" || !reflect.DeepEqual(detector.targets[0], []domain.ClientID{domain.ClientKimi})) { + t.Fatal("preview/apply map did not receive the selected version") + } + }) + } +} + +// Skills preparation and Check use this shared preview adapter with ordinary +// skillsOptions, whose dryRun flag is false. Only the mutation-aware CLI wrapper +// may request a new version; preview must reach its existing preparation gate. +func TestProjectDependencyPreviewDoesNotProbeVersions(t *testing.T) { + client := projectVersionClient() + detector := &projectVersionDetector{err: errors.New("preview must not execute a client")} + reachedPreparation := false + boundary := errors.New("inert preview preparation boundary") + adapter := &dependencyInstaller{ + app: App{ClientRegistry: projectVersionRegistry(t), Scope: domain.ScopeProject, Detector: detector, + StateStore: statev2.Store{Path: filepath.Join(t.TempDir(), "state.json")}}, opts: &options{}, + detected: map[domain.ClientID]domain.DetectedClient{domain.ClientKimi: client}, + beforeApply: func() error { + reachedPreparation = true + return boundary + }, + } + _, err := preflightDependencyAdapter(context.Background(), adapter, []dependencyAction{{ClientID: "kimi", Action: environment.ActionInstall}}) + if !errors.Is(err, boundary) || !reachedPreparation { + t.Fatalf("preview did not retain its existing preparation gate: %v", err) + } + if len(detector.targets) != 0 || detector.broadCalls != 0 || !reflect.DeepEqual(adapter.detected[domain.ClientKimi], client) { + t.Fatal("read-only Skills preview executed a client or replaced discovery facts") + } +} diff --git a/cli/internal/agentpluginscli/project_version_windsurf_test.go b/cli/internal/agentpluginscli/project_version_windsurf_test.go new file mode 100644 index 000000000..01c39815d --- /dev/null +++ b/cli/internal/agentpluginscli/project_version_windsurf_test.go @@ -0,0 +1,135 @@ +package agentpluginscli + +import ( + "context" + "errors" + "reflect" + "testing" + + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/domain" + "github.com/777genius/plugin-kit-ai/install/integrationctl/agentplugins/environment" +) + +func projectVersionDevin() domain.DetectedClient { + return domain.DetectedClient{ClientID: domain.ClientWindsurf, DisplayName: "original Devin", Status: domain.DetectionDetected, ExecutablePath: projectVersionFixturePath("bin", "devin"), Surfaces: []domain.ClientSurface{{ID: "devin_cli", Detected: true, Evidence: "original discovery"}}} +} + +func TestProjectVersionUnionIsIDBoundAtomicAndPreservesEmptyCascadeRoot(t *testing.T) { + for _, failure := range []bool{false, true} { + kimi, devin := projectVersionClient(), projectVersionDevin() + observedKimi, observedDevin := kimi, devin + observedKimi.Version, observedDevin.Version = "2.3.1", "3000.11.205" + observedDevin.DisplayName = "must not replace original display" + if failure { + observedDevin.ConfigRoot = "/invented/profile" + } + detector := &projectVersionDetector{probed: []domain.DetectedClient{observedKimi, observedDevin}} + detected := map[domain.ClientID]domain.DetectedClient{domain.ClientKimi: kimi, domain.ClientWindsurf: devin} + err := ensureSelectedProjectVersions(context.Background(), App{ClientRegistry: projectVersionRegistry(t), Scope: domain.ScopeProject, Detector: detector}, &options{}, []domain.ClientID{domain.ClientKimi, domain.ClientWindsurf, domain.ClientKimi}, detected) + if (err != nil) != failure || detector.broadCalls != 0 || !reflect.DeepEqual(detector.targets, [][]domain.ClientID{{domain.ClientKimi, domain.ClientWindsurf}}) { + t.Fatalf("finite union probe differs: %v %+v", err, detector) + } + wantKimi, wantDevin := kimi, devin + if !failure { + wantKimi.Version, wantDevin.Version = "2.3.1", "3000.11.205" + } + if !reflect.DeepEqual(detected, map[domain.ClientID]domain.DetectedClient{domain.ClientKimi: wantKimi, domain.ClientWindsurf: wantDevin}) { + t.Fatal("version merge changed identity facts or partially accepted a failed batch") + } + } +} + +func TestProjectDevinVersionProbeRejectsWrongIDAndUnboundResults(t *testing.T) { + for _, kind := range []string{"missing", "wrong-id", "duplicate", "version", "status", "error", "executable", "config", "profile", "authority", "probe-error"} { + t.Run(kind, func(t *testing.T) { + original := projectVersionDevin() + observed := original + observed.Version = "3000.11.205" + detector := &projectVersionDetector{probed: []domain.DetectedClient{observed}} + switch kind { + case "missing": + detector.probed = nil + case "wrong-id": + detector.probed[0].ClientID = domain.ClientKimi + case "duplicate": + detector.probed = append(detector.probed, observed) + case "version": + detector.probed[0].Version = "" + case "status": + detector.probed[0].Status = domain.DetectionNotDetected + case "error": + detector.probed[0].DetectionError = errors.New("observed failure") + case "executable": + detector.probed[0].ExecutablePath += "-other" + case "config": + detector.probed[0].ConfigRoot = "/different/legacy" + case "profile": + detector.probed[0].ProfileNamespace = "different" + case "authority": + detector.probed[0].ProfileAuthority = &domain.ProfileAuthority{} + case "probe-error": + detector.err = errors.New("targeted version failure") + } + detected := map[domain.ClientID]domain.DetectedClient{domain.ClientWindsurf: original} + if err := ensureSelectedProjectVersions(context.Background(), App{ClientRegistry: projectVersionRegistry(t), Scope: domain.ScopeProject, Detector: detector}, &options{}, []domain.ClientID{domain.ClientWindsurf}, detected); err == nil { + t.Fatal("unbound Devin version was accepted") + } + if !reflect.DeepEqual(detected[domain.ClientWindsurf], original) || detector.broadCalls != 0 { + t.Fatal("failed observation changed original authority") + } + }) + } +} + +func TestProjectDevinVersionProbeKeepsLegacyPrimaryAndMutationBoundaries(t *testing.T) { + for _, kind := range []string{"legacy-primary", "secondary-surface", "relative-executable", "known-version", "user", "dry-run", "unselected"} { + t.Run(kind, func(t *testing.T) { + client := projectVersionDevin() + opts, scope, target := &options{}, domain.ScopeProject, domain.ClientWindsurf + switch kind { + case "legacy-primary", "secondary-surface": + client.ExecutablePath = projectVersionFixturePath("bin", "windsurf") + client.ConfigRoot = projectVersionFixturePath("user", ".codeium", "windsurf") + if kind == "legacy-primary" { + client.Surfaces = nil + } + case "relative-executable": + client.ExecutablePath = "devin" + case "known-version": + client.Version = "3000.11.205" + case "user": + scope = domain.ScopeUser + case "dry-run": + opts.dryRun = true + case "unselected": + target = domain.ClientGemini + } + detector := &projectVersionDetector{err: errors.New("must not probe")} + detected := map[domain.ClientID]domain.DetectedClient{domain.ClientWindsurf: client} + if err := ensureSelectedProjectVersions(context.Background(), App{ClientRegistry: projectVersionRegistry(t), Scope: scope, Detector: detector}, opts, []domain.ClientID{target}, detected); err != nil || len(detector.targets) != 0 || detector.broadCalls != 0 { + t.Fatalf("ineligible Devin operation executed a version probe: %v", err) + } + }) + } +} + +func TestProjectDevinDependencyVersionsRespectCompleteActionSet(t *testing.T) { + for _, kind := range []environment.DesiredAction{environment.ActionInstall, environment.ActionUpdate, "repair", environment.ActionUnchanged, environment.ActionRemove, "invalid-later-target"} { + t.Run(string(kind), func(t *testing.T) { + client := projectVersionDevin() + observed := client + observed.Version = "3000.11.205" + detector := &projectVersionDetector{probed: []domain.DetectedClient{observed}} + adapter := &dependencyInstaller{app: App{ClientRegistry: projectVersionRegistry(t), Scope: domain.ScopeProject, Detector: detector}, opts: &options{}, detected: map[domain.ClientID]domain.DetectedClient{domain.ClientWindsurf: client}} + actions := []dependencyAction{{ClientID: "windsurf", Action: kind}} + if kind == "invalid-later-target" { + actions = []dependencyAction{{ClientID: "windsurf", Action: environment.ActionInstall}, {ClientID: "gemini", Action: environment.ActionInstall}} + } + err := adapter.preflightProjectVersions(context.Background(), actions) + wantProbe := kind == environment.ActionInstall || kind == environment.ActionUpdate || kind == "repair" + if (err != nil) != (kind == "invalid-later-target") || (len(detector.targets) == 1) != wantProbe || detector.broadCalls != 0 { + t.Fatalf("dependency version gate differs: %v %+v", err, detector) + } + }) + } +} diff --git a/cli/internal/agentpluginscli/repair_multi.go b/cli/internal/agentpluginscli/repair_multi.go index 497d67cb6..92e6d3760 100644 --- a/cli/internal/agentpluginscli/repair_multi.go +++ b/cli/internal/agentpluginscli/repair_multi.go @@ -161,8 +161,8 @@ func (session *repairManySession) revisionKey(binding domain.ClientBinding) (str } func (session *repairManySession) preflight() error { - _, detected, err := preflightSelectedTargets( - session.ctx, session.app, session.targets, nil, + _, detected, err := preflightProjectLifecycleTargets( + session.ctx, session.app, session.opts, session.targets, nil, !session.opts.dryRun && session.installation.OriginMode == domain.OriginModeDirectory, lifecycleInstallIntents(session.installation, session.opts.scope, nil), ) diff --git a/cli/internal/agentpluginscli/update_multi.go b/cli/internal/agentpluginscli/update_multi.go index 1a93debde..19858c176 100644 --- a/cli/internal/agentpluginscli/update_multi.go +++ b/cli/internal/agentpluginscli/update_multi.go @@ -122,7 +122,7 @@ func validateUpdateTargets(installation domain.Installation, scope string, targe func loadUpdatePackage(ctx context.Context, app App, opts *options, installation domain.Installation, targets []domain.ClientID, probeVersion bool) (map[domain.ClientID]domain.DetectedClient, []domain.DetectedClient, loadedPackage, error) { allTargets := installationTargets(installation, opts.scope) - _, detected, err := preflightSelectedTargets(ctx, app, targets, nil, probeVersion && installation.OriginMode == domain.OriginModeDirectory, lifecycleInstallIntents(installation, opts.scope, nil)) + _, detected, err := preflightProjectLifecycleTargets(ctx, app, opts, targets, nil, probeVersion && installation.OriginMode == domain.OriginModeDirectory, lifecycleInstallIntents(installation, opts.scope, nil)) if err != nil { return nil, nil, loadedPackage{}, err } diff --git a/docs/COPILOT_POST_ADD_REGISTRY_VALIDATION.md b/docs/COPILOT_POST_ADD_REGISTRY_VALIDATION.md new file mode 100644 index 000000000..59ccb8553 --- /dev/null +++ b/docs/COPILOT_POST_ADD_REGISTRY_VALIDATION.md @@ -0,0 +1,193 @@ +# Copilot post-add registry observation: candidate validation + +This candidate implements accepted plan SHA256 +`11faf859755a001ceb888f05ff3b071a0dbd9807b59618307168ac21ac191b4c`, +committed before code at `ca467438f13ea9aea9431c71aa7cf51f3922d8f5`. +The source/evidence base is `5781ef431714a1fb00dfa7a1c502e181699c9b54`. +Root and independent Kimi plan reviews both approved that exact plan. + +The genuine5781 capture completed public user add, then failed at its intentional +review barrier. It reports manual activation still required. Its raw post-add +native listing was absent, so this candidate adds one direct read-only +`[heldCopilot, plugin, list]` after the same successful public add, from the same +original outside working directory and HOME. It makes no production parser, +activation, ownership, trust, profile or qualification change. + +The new exact mode is `copilot-post-add-registry-first-capture`; its five fixed +commands are git-A, git-B, version, add-user and native-list. Each uses the +existing30second command path, unchanged150second work origin,180second total +origin, full descendant supervision, immutable pins and original config guard. +Public and list observations are separate ordinary phases. Their deferred +callbacks only read/project metadata and retain it; no deferred callback starts +a command. A fatal public guard cannot reach a list. A refused post-user or +pre-list metadata observation also stops before the fifth command. + +The two opaque metadata files independently retain the existing2KiB bound and +strict metadata walker/projection. They never replace the original config or +pin baseline. In particular, the five omitted profile changes in5781 remain +unknown. Native stdout/stderr are retained without parsing, trimming or +normalizing their registry text. Complete evidence has18members, including +the five original command triples and two separate metadata records. Earlier +failures retain only their exact finite prefix and truthful stage. + +The selected test deliberately fails at a raw-review barrier even when add, +list and both metadata observations complete. Actual t.Failed is serialized; +all five qualification flags, runtime, vendor authentication and real-model +qualification remain false. Unexpected probe/provider evidence is refused. +Existing user/empty/readiness modes and their helpers remain available for +their original evidence. Only the new finite dispatch/selection hooks and the +explicit current-selector expectation are changed in existing code. + +New inert contracts cover fixed command/stage/member boundaries, metadata and +public-progress requirements, exact opaque output, and actual original fatal +guards in the same Go test child with authored local scripts. They do not run +an acquired client, public installer or scanner and do not spoof hosted status. +The unchanged strict process guard requires the genuine supported hosted +environment; no local skip or weaker process assertion is introduced. + +Early development checks compiled the complete repotest package and passed the +targeted four new pure command/prefix/metadata contracts (`ok`,0.030s). The +affected new-mode/user/empty/readiness/runtime Python command passed54 tests +in6.348s. Their scratch logs are retained under +`/tmp/uap-copilot-post-add-dev-gates`. This execution used the working source +before its freeze/commit. It did not execute any strict OSRunner process case, +native client, public installer or scanner, and is not a local full-process +gate claim. Source formatting and Python syntax parsing are recorded separately. + +Final exact-commit local pure/compile/Python/lint checks, independent CODE reviews, +historical189e/922/2c2/5781 replay and the unchanged fresh hosted full unexcluded +Go1.26.10 Copilot process gate remain required. Publication must label the +fresh hosted gate pending until actual logs prove it ran and passed. Only a +new genuine capture and two independent raw reviews can support analysis of +its native registry bytes; no future parser or activation allowance is granted. + +## Exact candidate gates and publication boundary + +Final implementation commit `b05262fab01a1c5b56e557b63360e16a0b9d9ba8`, +tree `b7a3d11814ff80eacf6a02bd3506ac21c0678db9`, received independent +root CODE R1 GO (receipt SHA256 +`2f97b8986ff6a5d0b5c9b217a3708b3944e539206accd7172be17bb2857b8d66`) +and Native CODE R2 GO (receipt SHA256 +`65c658f333b78fe8bdfee3e99e71d0f6d2cda2b7ece8e8e263dd420897cffa92`). +Both reviewed the nine frozen paths and all 24 whole-file preservation anchors. +The gate receipt's earlier R2-pending note is superseded by that completed review. + +Measured final local gates on that exact code were four pure Go contracts +(4 RUN / 4 PASS / 0 SKIP / 0 FAIL, package 0.045s), complete repotest package +compilation, 67 affected Python tests (6.306s), affected all-enabled lint +and the whole unfiltered six-linter set (both exit0, zero issues). +The full current reader replayed original source-bound 189e, 922, 2c2 and +5781 archives without changing any member or result. Historical189e remains +readiness-complete with test_failed=false and all five qualification flags false; +the other three retain failed/incomplete tuples and all five flags false. +Final gate receipt SHA256: +`6b0015feb8fcfeebaa105eea96068df57888f50983273bd04926470dedff58a8`. +Historical replay receipt SHA256: +`75d48e512b2f483ccf38b3d9e05b01c699351c0c336a8558a5b6707ab727666b`. + +This publication appends only this validation record after the reviewed code. +The unchanged genuine hosted full, unexcluded Copilot/shared Go process gate +remains pending until its actual logs are checked. The local pure selection is +not a full process gate. Native execution remains solely in the supported +disposable hosted workflow. A successful raw observation still deliberately +fails at the review barrier; no activation, registry interpretation, runtime, +MCP, lifecycle, vendor-authentication or real-model qualification follows. + + +## Exact user live-listing repair and parent732 composition + +The original `85dfdaeaa217cf74f5c5a6464426cd1b67c2f069` native capture +completed the direct post-add listing and retained the disabled built-in section +followed by the exact enabled managed live entry. Public activation still +reported `manual_activation_required` / `package_validated`. Its 18 original +members and both independent RAW reviews remain historical evidence; they are +not a successful observation of this new production repair. + +The repair follows accepted plan SHA256 +`061e3db491efc478921c130f22ae1888638d6936ba61b3095ce5c7aa41c760df`, +committed before implementation at +`d95b6bb7ff03d835fa53b75348b4b63742f24bb6`. It adds one bounded, whole-byte +recognizer for the measured disabled `browser-use` built-in followed by one +exact enabled live entry. The new branch requires the held Copilot user scope, +identity, version, canonical managed path and executable, empty stderr and +original command/context checks. Registry ownership still depends on the exact +managed binding. Both hooks leave the existing generic and VS Code fallback +behavior intact. No production project activation, native fixture, reader, +profile baseline, acquisition pin or qualification rule is broadened. + +Independent reviews required test expectations to use an authored marketplace +identity and native platform paths. Corrected leaf +`d389a74ac1d1a3f54d3f52f0d55e182ed524a063` then received two CODE GOs. +Root composed it with program parent +`73208da2faae0f9cb20bf886d344ddc1c00fd648` at +`143d4477738b0615a240103f493c2e3898f13301`; two nonauthor reviewers independently +approved the exact composition. The original root and parent reader bodies, +client selection, source identities and historical qualification tuples were +preserved through whole-file and whole-tree comparisons. + +Final nested-SDK lint on143d found two actual `gocritic` issues. Candidate +`c02de25821d118df2d685ae11fa9a025c494065f`, tree +`95111cb74e2ec7bb548f52610708ac956eb25d65`, corrects only the equivalent +empty-string predicate and a checked test-owned extraction of the duplicate +live-entry fixture. All 5,975 other tracked entries remain exact143d, including +modes and Git blobs. Fresh independent CODE R1 and R2 receipts are SHA256 +`59bac872ad1a119534e01d34b3919819a9377f68c0d42d433670fda4c60de897` +and `4fb7f4b886602b3e798886a5033f3a0c95c3b255e27a1c1035648f17806721cf`. +The earlier failed lint and environment logs remain intact. + +Measured final checks on that exact clean c02 source: + +| Check | Actual result | +| --- | --- | +| Full affected shared/Copilot/providers/usecase SDK packages | 1,439 RUN; 1,435 PASS; 4 existing opt-in/capability SKIP; 0 FAIL; 37.099s | +| Combined parent/Copilot root selection | 513 RUN; 512 PASS; 1 existing capability SKIP; 0 FAIL; 18.430s | +| Twelve-module Python union | 186 PASS; all 186 historical unique test IDs present; 36.496s | +| SDK, root and CLI affected-all lint | All three exit0, zero issues | +| SDK, root and CLI whole six-linter gate | All three exit0, zero issues | +| Thirteen original/current complete-reader replays | 26 successful reader processes using nine exact original source snapshots | + +The four SDK skips are the existing locked-registry opt-in, two native-identity +containment capabilities and isolated installed OpenCode discovery. The sole +root skip is `TestGeminiCycleRepeatedRemovalPreservesActualSupervisorNaturalExit`. +These results do not establish full local process coverage. The complete SDK +and transitive CLI remain subject to fresh normal hosted CI. + +The final gate environment uses the existing task-owned Go/module/lint caches, +offline module resolution and original HOME. Only the four-package SDK test +command removes the six explicitly reviewed case-folded proxy variables. +The original143d restricted-sandbox socket/containment failures and read-only +module-cache failure are retained with their reviewed environment corrections; +no test assertion or selection was weakened. The final c02 run uses the known +inert loopback/process environment and correct caches from the start. + +Every replay preserves its original source commit/tree, outer and inner ZIP +hashes, closed members, full result dictionary and qualification tuple. The +five Copilot observations, four older parent regression captures, and newest +a544 Gemini/Cline/Kimi-component/Kimi-call observations were reread with both +complete original and current reader modules. No AST extraction or evidence +retargeting was used. In particular, original Copilot readiness retains all +five flags false; Kimi component and call lanes retain their distinct tuples. + +Final local gate receipt SHA256: +`106b1e53632441b20223cd93d969032e29e7ebced85d8a7d08f6e679c2195166`. +Complete replay receipt SHA256: +`f3dfcd3e8309957af659686cd7345abc9e9e4cb308c9b07f39fa03b61c8ac7c4`. +Root independently rehashed all nine gate receipts and raw logs, recomputed test +counts, and checked all thirteen original member inventories and complete +reader results; its verification receipt SHA256 is +`1c45847d33f9b2b797b8dcfcfc13def793740161b348c91cea0072f23e6e1934`. + +This publication adds only this measured validation section after the reviewed +code. Fresh published-head normal CI (`test-required` complete root and Core +Fast `make test-core` whole SDK/transitive CLI), the full unexcluded hosted137 +Copilot process gate, and actual native observations remain pending. The +unchanged 18-member Copilot capture deliberately fails at its review barrier +and keeps all five/runtime/vendor-authentication/real-model flags false. + +The fresh user repair must independently show public Active plus +`installation_verified`, without activation attestation or manual fallback, +and the exact enabled direct native listing. Authentication `not_checked` can +still produce `action_required=1`; that guidance alone is not a failed repair. +The internal Verify invocation's stdout and branch trace are not exported, so +no direct internal-branch observation is claimed. Two fresh RAW reviews are +required before a separately planned proper User/A/B project lifecycle cycle. diff --git a/docs/COPILOT_PROJECT_NATIVE_CONFIG_PREFIX_DIAGNOSTIC_PLAN.md b/docs/COPILOT_PROJECT_NATIVE_CONFIG_PREFIX_DIAGNOSTIC_PLAN.md new file mode 100644 index 000000000..0ee045bbb --- /dev/null +++ b/docs/COPILOT_PROJECT_NATIVE_CONFIG_PREFIX_DIAGNOSTIC_PLAN.md @@ -0,0 +1,132 @@ +# Copilot original config: bounded leading-comment diagnostic + +## Current source and actual failure + +Published PR527 source `f7421c5f1d6252dee7991b6bc34765663e277936`, tree +`65345a3d38219264db0f798ef3e3c491a216148a`, equals clean local +`c450dc9d5c86ecbfddb6d1ec563c071d9f6d507a`. Preserve its measured native +environment expansion, exact provider/probe identity checks, all external fixes +and original protected-config guard. + +Genuine runtime40456499106/job122033009727 failed at that guard after the +provider-returned flag became true. Native12712639477 outer SHA256 +`9ac80b05aea67079697538fed26bf5ac1986294c747bef647b35a99bb11dceb2`, inner +`29a79bdd280785c67f38d02952d8e1c8a88c35decfe09de3517e2dd007a8caad`, has21 +ordinary canonical unique members. Frontend12712809326 outer SHA256 +`bc5140f5d6e0aaf57c57e2925b9890baead353261157e149eba4794a928ded36`, inner +`b7425486ceea7e3fc5c9acf70388cd1555d01ea68a3b7dcb12dfa16e2720ae10`, has25. +API sizes/digests, archive closure/CRCs, all24 frontend command-stream hashes, +exact committed source/tree and empty patch list were independently checked. +The current native envelope re-admits as failed with all five qualification, +vendor-authentication and real-model flags false. + +Its finite diagnostic records baseline277 bytes/valid JSON and observed423 +bytes/invalid JSON, strict failure on the observed side, reason `syntax`. +Expected digest is +`a8a85b0ae210181acfedbf8d99319c00c4dde6792c3f9d7d04d7a9bb57983f62`; +observed digest is +`6ebd1de8072bf24f5d3ba857cf680caf17a19bd6eb57bb1b7591de9226a45eb0`. +No observed config bytes, prefix or semantic equivalence have been captured. + +## Hypothesis and evidence boundary + +The current primary [configuration-directory reference](https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-config-dir-reference) +distinguishes automatically managed `config.json` from user-editable JSONC +`settings.json`, and identifies trusted folders as internal config state. +It does not prove the bytes written by pinned1.0.103. An older upstream +[issue3403](https://github.com/github/copilot-cli/issues/3403) reports a comment +header at1.0.49; the bot says that issue was resolved at1.0.94. This is only a +reason to investigate a possible leading-comment format. It cannot establish +the current prefix, equivalence, or permission to accept changed config. + +This slice is diagnostic only. It neither grants general JSONC support nor +changes protected authority. In particular, parsing a suffix must never make +the native attempt pass or replace the original byte/digest baseline. + +## Finite implementation after two independent plan GOs + +Scope: the existing Copilot config diagnostic Go file, its existing contract +file, and this plan. No production adapter, shared parser, native environment, +argv, trust setup, provider, workflow, acquisition, source pin or other client. + +Only inside the current `invalid-json` branch, after the existing original +baseline digest check and one held ordinary bounded read whose digest equals +the already observed changed digest, add an optional finite prefix observation. +The baseline must already have parsed as a strict JSON object and the observed +error must be classified as `syntax`; other existing branches remain unchanged. +Do not perform a new filesystem read or extend the existing16KiB diagnostic +limit or original clock. + +Privately scan only a contiguous leading sequence of LF-terminated `//` lines +and JSON whitespace. Require at least one comment line, at most16 comment +lines, and at most4096 total prefix bytes; require UTF-8 and no non-JSON control +characters. Stop before the first non-prefix byte, which must be `{` for a +candidate object. Do not strip inline/block comments, trailing commas, BOMs, +embedded control data or comments elsewhere, and do not execute anything. +Use slices of the held body; no unbounded line collection or normalization. + +The new optional diagnostic object has a fixed schema and finite status: +`absent`, `prefix-refused`, `suffix-refused`, or `captured`. It may report only +bounded prefix byte count, line count, SHA256 of the complete exact prefix, +suffix byte count, the existing finite strict JSON failure category, and +optional exact semantic-object/trustedFolders equality booleans. No raw prefix, +comment text, JSON keys/values, parser error/context, arbitrary paths, provider +credentials or alternate configuration are emitted. Missing/failed comparison +remains unreported, not guessed false or assumed equal. Keep the complete +serialized diagnostic below its existing bound. + +For a candidate suffix, use the unchanged strict parser, including duplicate +keys, finite numbers, structure and trailing-data refusal. Compare the entire +parsed suffix object to the original strict baseline, and compare the exact +trustedFolders value separately. Do not coerce/sort/relax values. This private +projection does not change the outer `invalid-json` status, original syntax +facts, protected digest result, fatal guard, frozen config bytes or flags. + +## Meaningful inert controls and publication gate + +Exercise the actual diagnostic through its existing held-read seam. Cover +bounded complete leading-comment syntax with independently stated bytes/digest, +equal objects, changed trust, extra semantic fields, whitespace, private canaries +in comments/keys/values, malformed/duplicate/deep/nonfinite suffix JSON, inline +and block comments, BOM, missing LF, prefix byte/line limits and unexpected +trailing data. An injected canary must never appear in serialized evidence. +All existing no-read-on-guard-error, hash stability, original-baseline retention, +plain-JSON format diagnostics and hostile source/config controls remain active. +Prove that a captured equal suffix still returns the changed digest and retains +`invalid-json`; no semantic equality can satisfy the original fatal guard. + +Run focused affected inert Go contracts, all-enabled changed-line lint, +unfiltered whole-file size/complexity/architecture lint, format/diff checks and +the actual current failed Copilot-envelope replay. Use the exclusive validation +slot; no native client or positive hosted-eligibility guard runs locally. +Obtain two independent code reviews and fix findings before root-only publication +to the existing PR527 through a fresh real ref and expected-head lease. + +The fresh genuine capture must establish whether this hypothesis matches the +pinned client's actual output. Any later fixture-format or authority amendment +requires its own concrete source-bound plan/reviews. The complete user/A/B +lifecycle, restart/removal/repeated removal and actual native tool-session proof +remain required. No release/new PR or deferred VS Code work is included. + +## Actual implementation validation + +Shell and desktop independently approved the final plan SHA256 +`0db0c55dcd6502e0ce516189f8de34fc7882482f63515f9b2c2f11f5ab36cfd8` +before implementation, then reviewed the complete two-file code against the +separate plan commit `881d3dbab157e031741cbb165ac4fa20c8f24c11`. +Both gave final code GOs with no findings. Diagnostic source SHA256 is +`9ef2839d772a3bba46361e5d465729951948c95193ec05b22e163d9e11144f41`; +contract SHA256 is +`71fa655aa3a9aa89f1c3d0e4c27f83ab198685d03f27e24a06c22ef8c2ccc02d`. + +Focused Copilot and retained strict-runtime JSON contracts passed in `0.047s`. +The actual inert child exercised the original fatal guard for both whitespace +and equal-object leading-comment changes. All-enabled affected lint and +unfiltered whole-file size/complexity/architecture lint each reported `0 issues`. +Formatting and whitespace checks pass. The exact prior f742 native envelope +re-admitted with21 members and unchanged inner SHA256 +`29a79bdd280785c67f38d02952d8e1c8a88c35decfe09de3517e2dd007a8caad`: +failed/incomplete, all five qualifications false, authentication/model false, +and the original syntax diagnostic without hypothetical prefix evidence. +No vendor process or positive hosted eligibility guard ran locally. A fresh +genuine source-bound capture remains necessary before interpreting the prefix. diff --git a/docs/COPILOT_PROJECT_NATIVE_CONFIG_SUFFIX_MEMBERS_PLAN.md b/docs/COPILOT_PROJECT_NATIVE_CONFIG_SUFFIX_MEMBERS_PLAN.md new file mode 100644 index 000000000..00ad41297 --- /dev/null +++ b/docs/COPILOT_PROJECT_NATIVE_CONFIG_SUFFIX_MEMBERS_PLAN.md @@ -0,0 +1,102 @@ +# Copilot: finite member differences inside the measured JSONC suffix + +## Fresh source-bound observation + +At source9cd2e49e6db44c6561b983bfc96c8d3080b5f729, +treeb35dc7257820ca1817ea9b0093cad0c56fd29bfc, genuine runtime40462465006, +job122051849360 fails the unchanged original HOME/.copilot/config.json +digest guard after the scripted provider returned. The original trustedFolders +fixture is277 bytes. The changed423-byte file is not strict JSON. The already +reviewed finite prefix observation measures exactly two leading comment lines, +81 prefix bytes, prefix SHA256 +a432cd7c816a2ac01cdbd1b028e79f34d591d33e50346e8f2e2470e71eb56487. +The342-byte suffix is a valid strict JSON object. It is semantically different +from the original, while the presence-aware trustedFolders comparison is true. +This proves more than a formatting-only rewrite. The changed key/value is +not captured yet; do not guess a schema/default field or waive the fatal guard. + +Native artifact12716315019 is11880 bytes, outer SHA256 +b1302e041c8c9a28e3e8584c48bed96b7903936dba1289feee22557ebf604893, +innerc320f012181f8b121c3770d4b3f92d8bd1b9537ba233301168ca5edf44a279f7, +21 canonical ordinary unique members. Frontend12715209304 is3472 bytes, +outer9713c4cd4a3969c3f7c07c40cd860a5af3ac1d7097c80222ec2c1785f6be3668, +innerd1e954bd5a29a5d592ae1c80c2421e1f20379665646728c940af4e8ea669abc8, +25 members. Root checked API sizes/digests, closed ZIP/CRC, exact committed +source/tree with empty patch list and current failed/all-false admission. +The native/profile/authentication/model/lifecycle claims remain unqualified. + +## Bounded diagnostic extension after two independent plan approvals + +Scope only the existing Copilot diagnostic helper and contract file, plus this +plan. Extend the existing private leading_comment_probe after its original +held-read,16KiB cap, stable digest, bounded comment prefix and strict object +suffix checks. No new filesystem read, parse grammar or accepted outcome. + +Report before/after top-level field counts, total changed-field count and at +most three deterministic changed-member summaries. Each summary includes only +SHA256 of the member name, finite presence-aware before/after JSON types, and +SHA256 of the canonical JSON value for each present side. Sort by name digest. +Use the already decoded, duplicate-free maps and json.Number values; marshal +each held value canonically only for its digest, never export raw key/value or +error text. Existing trustedFolders presence/equality and whole-object equality +remain independent and mandatory observations. Include omitted count if more +than three members differ. Treat numbers as held strict JSON tokens; do not +coerce string/numeric/bool or absent/null distinctions. + +For this new suffix branch, bound the complete serialized diagnostic to2KiB, +including original hashes/counts/reasons and nested prefix facts. The older +strict-JSON branch with its existing32-member limit remains unchanged. +If the complete shape would exceed its limit, use a fixed no-detail refusal +or omit further summaries deterministically while retaining counts. Unknown +names/values/paths/URLs/auth text and their quoted error messages are never +rendered. The hashes are diagnostic evidence only, never new authority for +a guard, baseline, fixture setting or configuration acceptance. + +Keep outer status invalid-json, its original syntax reason, original fatal +digest comparison, parent deadline and all-false qualification unchanged. +The previously reviewed prefix acceptance/rejection grammar and its security +controls remain byte-identical. No normalizing/replacing the actual profile, +rewriting source pins or adopting vendor-produced trust/settings as authority. +A later fixture correction needs actual captured member facts plus independent +pinned source/documentation and its own reviewed plan. + +## Validation and actual follow-up + +Use independently authored before/suffix objects to prove add/remove/change, +explicit null versus absence, string/bool/number/array/object, exact unchanged +trustedFolders, deterministic reordered maps, more-than-three truncation and +the complete2KiB serialized cap. Include raw unknown private key/value canaries +and verify only independently expected digests/types/counts appear. Replay all +existing prefix/parser refusal controls and the actual original digest guard +test proving even semantic equality does not permit mutation. No standalone +test that only mirrors a helper is sufficient for the fatal-path contract. + +Run the focused Copilot inert diagnostic contracts and the actual affected +all-enabled plus unfiltered whole-file linters. Replay the held9cd21-member +failed envelope unchanged and verify all24 frontend stream joins. Obtain two +independent code reviews on the exact candidate and fix every finding. +Root publication uses a fresh actual ref and force:false for existing PR527; +no replacement PR, release, acquired local vendor execution or VS work. +Fresh genuine hosted evidence must identify the member difference before +any semantic interpretation or fixture-change plan proceeds. + +## Completed review and local verification + +The approved plan is local commit5cc3acf5; the implementation is2f0a28c3. +Two independent code critics approved exact diagnostic SHA256 +694a4db4dce6b86402ec57a61ca111ca3f6badbe9cb18687eb0e580802939753 +and contract SHA256 +1dc35e8262efa983206034c429b5329baf4bdc654c432808d27c053042d3890a. +Focused Copilot/shared inert contracts passed in0.054s. Actual all-enabled +affected lint from the approved plan and the unfiltered whole-file +revive/funlen/gocyclo/gocognit/dupl/depguard gate each reported zero issues. +Formatting and whitespace checks pass. The unchanged source-bound9cd envelope +re-admits with21 members, failed/incomplete and all five qualifications false; +all24 frontend stdout/stderr byte lengths and hashes were rechecked. +The new controls use the real protectedDigest path, independently stated +canonical value/name hashes, absent/null and numeric-token distinctions, all +JSON types,100 changed members in both object orders, exact omitted counts and +the complete2KiB bound. The original actual child-process fatal guard tests +still pass. No vendor executable, installer or positive hosted guard ran locally. +This diagnostic does not accept the changed original profile or establish a +runtime/lifecycle result. Fresh genuine native evidence remains required. diff --git a/docs/COPILOT_PROJECT_NATIVE_INSTALLED_TOOL_READINESS_PLAN.md b/docs/COPILOT_PROJECT_NATIVE_INSTALLED_TOOL_READINESS_PLAN.md new file mode 100644 index 000000000..719ba4dd9 --- /dev/null +++ b/docs/COPILOT_PROJECT_NATIVE_INSTALLED_TOOL_READINESS_PLAN.md @@ -0,0 +1,397 @@ +# Copilot: source-bound installed-tool readiness, without lifecycle qualification + +## Exact new genuine observation + +Current PR527 is `9b8ddc5332d70ca0c8d39c41c5ce60f3bba1c6e7`, tree +`8386a313607a2d1acfd5583bd9335d9ce7af1340`. Runtime40553325878, +native job122373176301, reaches only the deliberate native JSONL review +fatal at line433. All five public/native command receipts have exit0 and +no process/context/capture error. Native execution took723ms; the complete +attempt took3841ms. The original authored firstLaunchAt/configuration digest +guard passed in the exact reviewed source. Those original file bytes are not +exported, so their preservation remains source-attested live evidence. + +Native12760476935 has21 ordinary closed members, outer SHA256 +`bc595e6e56049a1f3a642159ef6032c5fc702e386360b66494ccffb83557e3e1`, +inner `37bb4526d83f77857c203b9ec75a695c93ac57ae323e2f6830b2ade75bbbc9f9`. +Frontend12760127067 has25, outer +`402416a285dbd853390ccbc4fa4a5059856bfd9e2881af09d4ef3f35bd9768f9`, +inner `498c7f7d7a9b35e85e612323b77fdfbe5dbb9d2d6c11cc451fec8ea6050d5a88`. +Independent checks verified API sizes/digests, ZIP names/types/CRCs, exact +source/tree/clean records,24 frontend byte/hash joins and pinned acquisition +identity. All native/frontend qualification, account and model flags remain +false, and the historical capture stays failed. + +Raw files are under `/tmp/uap-copilot-9b-raw-cpw606qd//raw/`. +Independent semantic report SHA256 is +`d380dc0c1c2584ccbdcd9594cd34dbc7e365bbf3c51640fb59c28afc05ac1e6f`. +It joins27 native frames,26 unique event UUIDs, native result session UUID, +two provider requests, one exact workspace MCP call, and three independent +probe events. All11 facts, original HOME expansion, installed launcher/root/ +data/argv, owned skill body/digest and selected native catalog agree. The +two native builtin skill rows and five disabled builtin MCP rows do not count +as owned discovery, activation, calls or additional authority. + +## Measured finite grammar + +Author a small client-specific strict parser around these actual bytes, +using the existing duplicate/UTF8/nonfinite/bounded JSON decoder and the +existing process/output bounds. Preserve the27-frame sequence and closed +outer/data key sets from the retained capture; every unknown, missing, +duplicate, reordered or wrong-type event remains a refusal. No incoming +value is trimmed, rewritten or adopted into fixture expectations. + +The finite sequence includes MCP pending/connected/tools-loaded, skill and +server catalogs, disabled-tool configuration, user message, two assistant +turns, the sole tool request/start/complete, final sentinel and result. +Validate typed UUID event/parent fields and measured exported relationships; +do not invent a requirement that every parent ID equals the terminal session +ID, since the actual stream does not have that property. Native turn IDs are +the exact strings0 and1 for this fresh single-prompt exchange. + +The authored argv prompt equals native user.content. Provider request1's +user content equals native user.transformedContent, not the untransformed +prompt. Request2 preserves the first history and non-message parameters, +adds exactly one selected assistant call and its matching tool result. +Require the same provider-owned call ID/name/arguments across the delta, +assistant request, execution-start and execution-complete records. The +terminal native session UUID is validated independently; it must never be +derived from provider call, probe PID/session or event parent IDs. + +Join all three native result representations (content, detailedContent, +single contents text), provider tool history, summary facts and independent +initialize/list/call events. Bind all11 facts to the held nonce/source/ +revision/binding/data/argv/HOME expectations, retaining literal variable +behavior exactly. Require the observed sentinel after one call, no extra +tool request, successful final result and zero code-change summary. Validate +bounded nonnegative typed telemetry; isByok describes the scripted loopback +route and never qualifies account authentication or real-model execution. + +Validate the exact owned project skill name/path/description/enabled/source, +its installed body and ownership digest, and the selected workspace stdio +server. Keep the observed builtin metadata separate with exact known names, +paths and finite fields; do not claim builtin file hashing or skill prompt +activation from these catalog rows. Preserve the exact disabled-tool message +and original narrowly selected native argv and permissions. + +## Finalization and admission boundary + +Use a separate mode such as `copilot-installed-tool-readiness`; preserve old +failed-only admission unchanged for envelopes without this new mode. The +new mode permits only paired failed/incomplete or passed/complete states, +with all five qualification flags always false and account/model flags false. +Client/version/pins, source/tree/empty patches,21 exact members, all five +command triples, two provider requests and native/probe/installed artifacts +are required for success. Recheck semantic joins in a bounded client-specific +Python reader; structural or contradictory success is refused. + +Capture native command start/end UTC instants directly around the existing +supervisor call as fixed summary fields, without changing its receipt schema +or deadline. Use the original interval for native/probe time validation; +retain each wire timestamp's actual precision. This is new observation, not +a reconstruction of missing start/end fields in the old capture. + +Remove only the deliberate grammar-review fatal after strict native parsing, +ordinary provider closure and current two-request/returned-facts checks. +Set candidate observation separately from completion. Finalization must first +clear completion and all five qualifications, then require no test failure, +original work context alive, original total bound, full captured closure and +all existing immutable/profile checks. Late failure must retain incomplete +status. Outer frontend still requires the actual selected test PASS, ordinary +process closure and strict admission before collection_complete; it never +turns an admitted failed test into success. Archive/write failures remain +test failures. Do not edit or relabel the old captured failed artifacts. + +This completes only the installed single-tool readiness attempt. It does not +prove user/A/B coexistence, repeat/update/repair, fresh restart/removal or the +five requested lifecycle/MCP qualifications. Those require a separately +reviewed full-cycle first capture and later genuine completion evidence. + +## Scope, reviews and checks + +Scope is Copilot's existing attempt/provider seam only as necessary, bounded +new client-specific parser/contracts, a separate Python mode/admission helper +and contracts, hash-bound actual raw test fixtures, and a truthful accepted +plan/validation record. Preserve old tests/entrypoint/pins/host/process/ +scanner/trust/credential/permission/source/data/privacy gates and150/180s +budgets. No production adapter, new workflow, broad process framework, +account authorization or VS Code-specific change is included. + +Keep the separately reviewed nine-lint correction in its own commit; do not +silently combine semantic changes into that mechanical review. Obtain root +R1 and another independent plan review before code, then independent exact +code review. Replay the actual27-frame/two-request/three-event capture and +exercise foreign IDs/roots/calls, extra or missing actions, type/unknown-key, +history/result mismatches, metadata/builtin confusion, privacy and late +failure controls. Tests are inert; never execute a vendor/public installer +or fabricate a positive hosted guard locally. Run the meaningful focused +Go/Python contracts and affected/whole-file lint in the coordinated slot. +Root alone publishes on a freshly reconciled PR527 head. A fresh genuine +successful readiness run is required before its completion can be reported. + +## Accepted implementation boundary (2026-10-27) + +Root R1 and independent native-CLI R2 approved proposal SHA256 +`4b220367cbb3acc7a3c14b2a18c8e45a73d4302e0e2635f5bc931c4334ec1c16` +before implementation. The separate mechanical commit retains its separate +33cf3a7e plan and reviewed one-line executable-mode fixture amendment. + +The checked-in21-member raw fixture remains the original deliberately failed +9b8d source/run40553325878 capture, with its exact member hashes bound by +manifest SHA256 `807b961c1f4280081cc4a9c2d2c28c4997147b1df0985678cf0ace91e938703a`. +No raw fixture bytes or historical summary are relabeled. The explicit inert +replay interval18:31:21.7Z–18:31:21.9Z encloses exported events; actual old +command start/end instants were not exported and are not inferred as evidence. +The live fixture now records actual supervisor command start/end UTC instants. + +New client-specific Go and Python readers enforce the finite27-frame grammar, +26 unique event IDs and measured exported parent groups/edges, separate native +session, exact metadata/catalogs, original/transformed prompt distinction, +one-call two-turn exchange, three identical result representations, complete +provider history and parameter equality, exact11 facts and three independent +probe events within the original command interval. The authored installed MCP +entry and skill bytes are independently reconstructed; native MCP codec/name +framing and the one-file non-executable skill framing bind ownership digests. +Builtin hashes describe measured description metadata, not builtin file hashes +or prompt activation. Installed files join the existing protected authority +set only after these independent checks. + +Finalization clears completion and all five flags first, rechecks immutable +and original/protected bytes, requires the original work context, original +180-second total bound, full20-member pre-summary capture and ordinary closed +provider before publishing readiness completion. Observed candidate facts are +separate from completion. Late failures remain failed/incomplete; outer actual +Go PASS and ordinary process/capture/admission gates remain mandatory. Archive +or output errors fail the test, so no admitted success can override them. +No account/model qualification is added. Full user/A/B lifecycle is outstanding. + +The historical failed-only Python admission remains unchanged for old +envelopes. The new exact mode permits only failed/incomplete or passed/complete +with all five lifecycle/MCP flags false. It rechecks current source identity, +exact21 members, all five command triples, acquisition/scanner/source/binding/ +installed/public receipt authority and every exported native/provider/probe +semantic join. Contradictory structural success is rejected. + +Validation and independent exact-code reviews must finish before root +publication. No vendor or public installer executable is run locally. + +## Independent code findings closed + +Root's independent code review found that the new Python reader accepted an +unchecked source_binding_id. Native-CLI review separately found UUID/pattern +checks without derived joins for public installation, physical package, client +binding and data receipt identities. These were concrete inert counterexamples, +not newly observed native behavior. Both findings are corrected within the +approved exact source/binding/data authority boundary. + +The reader now derives the no-repository direct-local source ID from the held +canonical source path followed by two NUL bytes, using SHA256 first12bytes. +The live fixture independently requires that ID, the exact requested/canonical +source and absence of repository/subpath/revision/alternate source metadata. +The reader derives physical package, client and data IDs from the public +installation ID using the current exact domain/provider framing. The live +fixture performs the same independent joins from its held installed receipt, +requires the state map key and exact one data receipt, and checks the exact +data ownership digest and selected paths. Literal independently reconstructed +positive controls and foreign/missing/type/source controls cover the source +ID. Distinct controls replace the public UUID, coherently replace client and +receipt references, replace the data ID, physical ID, locator/scope and +ownership digest. Historical raw fixture bytes remain unchanged. + +The separate exact-role semantic change was reconciled after the mechanical +commit; current root R1 and native-CLI R2 plan/code reviews approved the exact +five-role switch and14 actual full-request controls. Imported historical +review timing claims were explicitly corrected rather than treated as proof. + +## Current-base preservation and validation + +A true merge of current program base a412ba5e137fdcb7e004393229b323211ed746e1 +is recorded as2ab933ce. Its only conflict was the shared held-file runtime +helper: full comparison proved the Cline base was a strict superset, so the +merge retains that exact base blob. The shared Python automatic merge retains +all14 Cline functions from the base and every prior Copilot/common function; +only cline_members and cline_service_argv intentionally take their base +versions. All38 other own changed files remain byte-identical across the +merge. The static preservation report has SHA256 +`4ca8e166f6b4d3e4bd1906d9082d468f69f80ef861b489c367d126758262b3ae`. + +Post-base focused Copilot/shared Go contracts passed in0.218s. The new +Copilot, shared-runtime and preserved Cline-cycle Python contracts passed +all39tests in10.256s. Initial leaf focused contracts passed in0.253s; initial +all-enabled root lint against443fa8d and unfiltered whole-root six-linter +gate each reported zero issues. Post-base final lint and independent exact +code reviews are recorded after those gates; no vendor or public installer +executable has been run locally. All five qualification flags remain false. + + +## Accepted exact disabled-builtin empty-registry amendment — 2026-10-27 + +The following pre-code snapshot is accepted unchanged with SHA256 +`eca2d5c8d5a29b8a0ce08566cbc3f0712013029db87700cac38ebeea0e2dfd65`. +Independent root PLAN R1 receipt SHA256 +`15246b2c626984d5efeebb68a9588e2d50efe99a209da86bf5aecc70c4267e18` +and Kimi PLAN R2 receipt SHA256 +`ef27761b4615849804c4c95d5993065923a02af3122d47c6e51cbaa9d59f08be` +both approve this exact source2c2/tree2a95 plan before code. + +Both reviewers independently checked the measured138-byte literal, caller and +parser source, raw captures and all15 baseline hashes. The new absence branch +must explicitly refuse a canceled context even if the inert runner returns +exit0/nil error; this implements the plan's existing cancellation requirement. +Affected production checks/lint run in its nested +`install/integrationctl/agentplugins` module, alongside root dispatch contracts. + +The inherited Cline job subsequently completed SUCCESS at23:26:07 UTC and its +original source-bound54/31-member archives were preserved and independently +audited, receipt SHA256 +`8d67bee35c2bd5bf97ea84f91f5ba43948dea7df990e8529244b69929ab53491`. +The draft's queued observation below is historical. No pending capture remains +on current run40599529602; fresh remote reconciliation is still required before +publication. Copilot's actual2c2 diagnostic remains failed and allfalse. + +# Copilot: exact disabled-builtin empty registry and return to public-first-add capture + +PRE-CODE plan. No source implementation before root and a second independent reviewer accept this exact plan SHA, and root commits the accepted plan before code. Root alone performs Git/GitHub mutations and publication. No acquired Copilot/native client, public installer, scanner or vendor executable runs locally. No VS Code implementation/native work, release, pin, workflow, supervisor, authority or budget change. + +## 1. Exact source and actual evidence + +Base is `/tmp/uap-copilot-empty-registry-current`, source `2c2ac7f1758514f61fc1c88cabc4ad89d6612625`, tree `2a952c617665f50440b28166dac4c5eb103b5c28`. Current hosted run40599529602 admission122523885961 passed. Native Copilot122529435619 completed failed at23:20:04 UTC. Its only failure is the intentional empty-registry review barrier after all four clean commands. Inherited Cline122529435647 was still queued at the last observation; do not cancel, rerun or supersede its capture. Root may review/prepare local code, but must preserve and finish auditing that current genuine capture before a new publication could supersede it. + +Original artifacts/API identities are preserved under `/tmp/uap-copilot-2c2-current-40599529602/`: + +| Artifact | ID | Outer SHA256 | Inner SHA256 | Members | +| --- | --- | --- | --- | --- | +| Native | 12778157833 | aa359f598666bc29904fa40121a4657752a6fc2532b9fd99282adb4692f8b349 | af3932d322e83e23c8cb751dbde26edc8c80412eabb1dde03eda71286931d50b | 14 | +| Frontend | 12778237718 | e9f571e1de2b52b5b40702ec9c227c3f6d05b8d435cdf7fdcde26da3c44f2ffc | eefb289989dc8cc0418591da05ceefc5083feb202e72a0994adab697af133961 | 25 | + +Both independent actual raw reviews are complete: + +* Peer `/tmp/uap-copilot-2c2-current-40599529602/independent-raw-audit.json`, SHA256 `56874f33edd8794ab581bb9c3f08fc4d488cf877c6360d8051ae2d585f92c04f`. +* Root `/tmp/uap-copilot-2c2-current-40599529602/root-raw-audit.json`, SHA256 `c0eda8adb39a7881863954145683346dd082cff7cf40f5df811d81d0e25848b7`. + +These verify closed ordinary ZIPs/CRCs/API digests, source/tree/clean build/pins/scanner,24 frontend stream joins, fixed git-A/git-B/version/native-list commands and allfalse failed-only output. Native elapsed2858ms; direct plugin-list elapsed558ms, exit0/errorfalse/contextfalse, empty stderr. The only frontend failure is line141 of the inherited source-selected test, the deliberate review barrier. No provider, prompt, native tool session or probe event occurred; probe_status is absent. + +The version output is exactly71bytes, SHA256 `0381297224b3ae763df6f5434597b39b5ea5d26a42cab604ad8d346d69487237`: + + GitHub Copilot CLI 1.0.103. + Run 'copilot update' to check for updates. + +The direct native list output is exactly138 UTF8 bytes including one final LF, SHA256 `f09cb232e9a7f7bd379daed96099ea1fdf8f6644dcc390ce43c7854874d7e879`: + +```text +No plugins installed. + +Use 'copilot plugin install ' to install a plugin. +Built-in plugins: + • browser-use (v0.0.4) [disabled] +``` + +This is one observed whole tuple. No enabled builtin, other builtin/version, arbitrary suffix, generic section-skipping rule or future CLI output is established. Native pins remain official1.0.103 archive9aeb4430e9ac9523546db07b227c7aba179a4710a55f9ac29ad143b0f9e1b325 / executablef19b3554a6b62605db3a26d5255ebe2a3ee39fcd6a357edb18301ea5037f6f0d. + +Metadata is1037bytes, SHA256 `76dc472f8cfbaf88c89b2335a55aab4abe9d646bce893a517b7307b710eee023`: before2/after4,3changed/0omitted; one added directory0700, one added file0600 and one changed held directory. It contains hashed paths and metadata only. No filenames/content are inferred and no profile exception or baseline renewal follows. Original held configuration checks did not fail in this diagnostic. The metadata limits and all guards remain unchanged. + +The completed hosted full inert gate is independently recorded in `/tmp/uap-copilot-2c2-hosted-inert-proof.json`, SHA256 `e6f33a946c28d38771c6936e0f1aa4e3c04e104d3324e9da70c03381c7f1b381`. Raw log SHA256 `c1551e204f1c21779c9a35dd8ff848621a6b4abe176ecf9fcd94476f3085cafc` proves both unchanged strict process tests actually RUN/PASS, no skip, underGo1.26.10 and the full no-exclusion command. This is historical source2c2 gate evidence, not proof of a future source or native qualification. + +## 2. Current parser refusal and client scope + +This explicitly changes a production parser/preflight decision. It is not a diagnostic-only edit. + +At this exact source, `shared.CopilotRegistryFindingAt` first tries the live-plugin grammar. The actual first line is not CopilotLiveHeader, so that branch does not recognize it. `copilotInstalledListingFinding` recognizes only the older whole empty-registry document without the builtin suffix. The138byte document therefore misses that fast path. Its first line is not Installed plugins:, and `copilotListingScan.consume` immediately returns RegistryIndeterminate before a section header. Both independent source reviews establish this exact branch path. The diagnostic itself did not execute that production classifier; no failed-public-add branch is inferred merely from the diagnostic summary. + +Caller review matters because the shared registry inspector serves both Copilot and deferred VS Code. `clients/copilot/identity.go` calls `shared.InspectCopilotRegistry` only after its existing project-scope path has returned; its user operation carries `DeliveryPlan.ClientID=ClientCopilot` and user scope. `clients/vscode/identity.go` also calls the shared inspector, with ClientVSCode. Native identity dispatch selects the adapter from the detected client ID. DeliveryPlan contains explicit ClientID, Scope and TargetContext.Scope fields. + +The new admission must be Copilot user-only. Preserve every generic/live/installed classifier and old test byte-for-byte. Do not edit any VS Code source, tests, routing, workflow, evidence or PR530. A negative shared-unit control using ClientVSCode tests this exclusion; it does not establish VS Code runtime support. + +## 3. Small production change + +In `install/integrationctl/agentplugins/clients/shared/copilot_identity.go`, add one narrow branch in the existing `inspectCopilotCLI` path **after** the unchanged RunNativeRegistry call, context/error handling and zero-exit requirement, and **before** the unchanged generic finding call. + +The new branch requires all of: + +1. `plan.ClientID == domain.ClientCopilot`. +2. `plan.Scope == domain.ScopeUser` and `plan.TargetContext.Scope != domain.ScopeProject`. +3. The entire stdout equals exactly the measured138byte UTF8 tuple above. + +4. The held requested DeclaredName is nonempty, has no leading/trailing whitespace, and is not equal to browser-use under case-insensitive comparison. This refusal is conservative: the captured disabled builtin establishes that name exists in a separate native namespace, but supplies no primary-source evidence about collision or ownership semantics for a requested plugin of the same name. The current UAP fixture has a different declared name. A same-name request (including case variants), blank/noncanonical name, or uncertain identity falls through to the unchanged generic parser and remains Indeterminate for this tuple; it cannot be silently declared collision-free or owned. + +Only then return RegistryClear for the unrelated requested plugin. Retain this absence result for both owned and unowned unrelated expected identities, as with the old recognized empty formats. No installed/active/authenticated or builtin ownership claim is introduced. No environment variable, test marker, native version string, package pin comparison or executable basename selects this branch: the authority is exact whole raw output after the ordinary successful command plus held client/user-scope/nonbuiltin-name context. + +Use a small private exact-byte predicate or literal comparison; no general output splitter, section extractor or configurable exception. For the new tuple do not trim whitespace, strip ANSI, normalize CRLF, accept a missing/extra LF, ignore prefixes/suffixes or search for the no-plugins sentence. Existing normalization and old empty formats continue through the original generic classifier unchanged. + +All other client IDs, missing/unknown ID, non-user scopes, project target context, changed native output, nonzero exit, runner/context error and no-CLI fallback retain existing behavior. In particular, the measured tuple stays RegistryIndeterminate for ClientVSCode and the public generic classifiers remain RegistryIndeterminate for these same bytes. Existing recognized installed/live/empty formats retain their current expected/collision/clear/indeterminate classifications. Existing native command argv, one-second full-tree exit grace, runner selection, deadlines and error propagation remain exact. + +A Copilot-only guarded branch in this shared call site is the proposed minimal implementation. If concrete implementation evidence shows client/scope identity is not reliably held there, stop for amended review; do not replace it with a generic shared output allowance or silently widen the adapter API. + +## 4. Return to original public-first-add capture + +Change only `CASES['copilot']` in `scripts/project_native_runtime.py` to the already-existing entrypoint: + +| Field | Exact value | +| --- | --- | +| test | TestAgentpluginsCopilotNativeUserRegistrationFirstObservation | +| file | repotests/agentplugins_copilot_user_registration_attempt_test.go | +| optin | AGENTPLUGINS_COPILOT_USER_REGISTRY_FIRST_CAPTURE | +| seconds | 180 | +| phase | runtime-attempt | + +Update only the exact selection expectation in `scripts/test_project_native_copilot_user.py` and, if necessary, a directly related source-selection assertion proving a single canonical Copilot case. Preserve the remainder of its historical outcome/contracts. Keep the empty-registry test and failed reader callable and byte-identical; do not keep them selected as an additional native lane. All current other-client selections stay exact. + +The selected original test remains wholly byte-identical. It creates a fresh original profile and fixed package, then executes git-A/git-B/version and exactly one public `agentplugins add --no-save --scope user --target copilot --format json` from the original outside cwd. No direct native list warmup, pre-registration, fixture registry entry, profile/body adoption, fallback add, provider, prompt, probe or additional command is introduced. The public add's own ordinary production preflight performs the one current registry read as before. + +Its original command/config/process guard, deferred metadata projection, strict public JSON check and deliberate final review barrier remain exact. It remains failed-only/allfivefalse/runtimefalse/authfalse/modelfalse even if the public add reaches its intended barrier. If the unchanged guard fails earlier, retain the original fatal failure and evidence; never continue past it. Activation/user registration/native installed-list grammar or later lifecycle qualification is not inferred in advance. Any genuinely new failure requires its own source-bound raw review. + +No workflow edit is needed. The inherited exact Copilot conditional setup-Go and full no-exclusion process gate remain in admission; native still depends on that gate. Keep both actual strict process tests and all prior capability refusals unchanged. + +## 5. Narrow source surface and preservation + +Expected code paths are: + +* Existing production `shared/copilot_identity.go`: one guarded exact observed tuple path; all generic classifier function bodies preserved. +* One new focused shared Copilot unit contract file: exact production routing and adversarial tuple/client/scope controls with an inert in-memory runner, no child process. +* Existing runtime Python: only the five Copilot selection fields above. +* Existing `test_project_native_copilot_user.py`: exact selected test/file/optin expectation and narrow related preservation assertion only. +* Accepted plan and concise validation documentation. + +Existing `shared/copilot_identity_test.go`, shared status/lifecycle/native registry runner, Copilot/VS Code adapter files, project identity/config/activation/removal paths, public installer flow and all existing repotest guards/readers stay byte-identical. No native capture/log/executable fixture goes into Git. The test may independently author the exact public138byte text as a small parser contract with fixed length/hash, clearly distinguishing it from a new native run. + +## 6. Meaningful validation and failure preservation + +Before code obtain two independent exact-plan GOs and root's pre-code commit. Work only in a root-created isolated current-source checkout; no Git/GitHub mutations by the author. Root coordinates all Go/Python/lint slots. + +New focused inert unit contracts must call the actual shared registry-inspection production path through a held in-memory CommandRunner, asserting exactly one `[selected-copilot, plugin, list]` invocation and original error propagation. They must independently check138 UTF8 bytes and the golden SHA256, then establish Clear only for actual Copilot user-plan context. Test both owned/unowned unrelated expected identities; the output admits absence and cannot imply managed expected activation. Explicitly refuse requested browser-use, case variants, blank names and names with leading/trailing whitespace for this tuple; there is no source evidence that its disabled builtin is free for a same-name install. + +Use direct meaningful negative inputs: enabled/missing status, changed browser name/version, extra builtin, duplicate row/section, arbitrary prefix/suffix, extra/missing LF, CRLF, ANSI/NUL, changed no-plugins/install-guidance text, installed entry mixed with empty text, truncated tuple, other/missing client ID, requested browser-use/case variants/blank or whitespace names, non-user scope and project TargetContext. Changing an environment or claimed native-version value must not alter the result: no such input gates the predicate. For ClientVSCode and the generic pure classifiers, the exact new tuple must remain Indeterminate. Old official empty output, old Installed plugins empty/installed forms, live enabled/disabled identity/version/path and unknown suffix behavior keep their prior classifications. Preserve old generic test source unchanged rather than rewriting their expected outcomes. + +Runner failures/nonzero native exits and cancelled context must remain Indeterminate/error and cannot reach the new Clear branch. No native/user profile writes occur in these unit contracts. No process/environment marker impersonation. + +Execute the new focused production shared Copilot tests and existing relevant old shared Copilot tests, affected runtime/selection/user/empty-reader Python contracts, gofmt/whitespace, affected all-enabled lint againsta412ba5e137fdcb7e004393229b323211ed746e1 and whole unfiltered revive/funlen/gocyclo/gocognit/dupl/depguard. Add broader tests only for a concrete remaining risk. Keep the existing full hosted command `go test -json -p=1 -count=1 -timeout=120s ./repotests -run '^(TestCopilot|TestProjectNativeRuntime)'` exact; new published source must actually pass this gate before native execution. Do not claim the historical2c2 hosted pass as a new-source pass. Do not rerun unchanged known-incapable local strict process tests solely to reproduce the missing/proc limitation, exclude or weaken them, or introduce a new host approval recipe. Preserve the original local failures and historical actual hosted proof; use byte-identity to transfer unchanged local/inert checks only where root explicitly records that transfer, and require the existing fresh hosted full gate on publication. + +Scratch pure readers replay historical189e readiness,922 user-registration failure and2c2 empty-registry capture with their original source identities. Preserve archive/member/raw hashes, failed/pass distinctions and allfalse qualification outcomes. The production parser change does not retarget or promote any old capture. In particular,922 remains the actual failed public-add observation, and2c2 remains the deliberate failed diagnostic. Every failed-only reader/mode remains unchanged. Record actual commands/exits and log digests rather than anticipated counts. + +After frozen source, two independent CODE critics must verify the production scope guard, exact literal/hash, all unknown refusal, unchanged generic/VS Code paths and original first-add command/guard/reader bytes, then review actual gates. Root alone reconciles current remote/pending capture state and normal-FF publishes after both reviews and measured gates. No manual unchanged-source retry or supersession of pending Cline. + +Fresh genuine current-source public-first-add capture is required. Independently audit API/source/tree/pins/closed frontend/native receipts, exact public argv/cwd/exit/stdout/stderr, original profile/metadata/guard/cleanup and failed-only boundary. A new public first-add failure or intended barrier remains failed and unqualified. No native runtime, user activation or five-flag completion claim follows from this parser amendment. + +## Baseline hashes + +The following exact source hashes bind the preservation promises. An unchanged function within the production identity file will also be independently compared as complete bytes before code approval. + +| Path | SHA256 | +| --- | --- | +| `install/integrationctl/agentplugins/clients/shared/copilot_identity.go` | d784b9e56c45e72f95deac76ae1a5e9b7930673b50979959e3a4523c056ad6e3 | +| `install/integrationctl/agentplugins/clients/shared/copilot_identity_test.go` | aea80041bc701a5813a3be96773a7ef849701ad3ca39ee10bfa66ecdfa00005c | +| `install/integrationctl/agentplugins/clients/shared/copilot_status.go` | 7fb2f5f03491f036d613217284c830a87efebfe15827038fa43401417be69ec4 | +| `install/integrationctl/agentplugins/clients/shared/native_registry.go` | 9be2175d88e1ab6eeee8d1f0b812fafee5d43a5a67fc039abfd675cef2caa115 | +| `install/integrationctl/agentplugins/clients/copilot/identity.go` | 7bb1a7a467fe4265b3fb20ce06f7339ed3ca225cb25547264a31481f2b9c4094 | +| `install/integrationctl/agentplugins/clients/vscode/identity.go` | 53dc07b8c0a83c378bc9e8ee11d280a191b101839bea63c0985b7ad518d63167 | +| `repotests/agentplugins_copilot_project_native_attempt_test.go` | 8cc6cfdc416259c09852873274b07098c9f6ccd43e6b7f919a5f0b4afcad7be0 | +| `repotests/agentplugins_copilot_user_registration_attempt_test.go` | 45447d0a35f8dede1f95d505f098c4485f3695402f76ccdfabd0e4100a8cb36d | +| `repotests/agentplugins_copilot_empty_registry_attempt_test.go` | 9e78c5fb43db2ecf4007e9dd271a4aa26010f75b96879cb30633e4419e8e3caa | +| `repotests/agentplugins_copilot_empty_registry_process_contract_test.go` | d328951b55a897eeb81783216a80d6f7f8d2fbcee3328b9f491d2d6dab210b6c | +| `scripts/project_native_copilot_user.py` | fe75f19d141b755bf19c1ee7605963fa2f045bdcbca5690b38ea044609bb42c5 | +| `scripts/project_native_copilot_empty_registry.py` | 4bbf4e5e34ff8e908a867744beb14228fadfc5e91d8aacc60b242a8f96f1922e | +| `.github/workflows/project-native-runtime.yml` | 6d50637892ee2a387052b42d5d9a53a8db68e7a54aa2d04272f49425cb17e3df | +| `scripts/project_native_runtime.py` | 92d318fc834f3ebdb935daf7bcab21bdf5549899d63ad53820964ee77589d435 | +| `scripts/test_project_native_copilot_user.py` | 285babe9bfc2e34aff6cf5edb50cb82ee5b9e7bb621d41e6a3b0ef5f782551d4 | + +Draft author performed source/raw reads and wrote this scratch plan only. No implementation, test/gate/native execution or Git/GitHub mutation was performed for this proposal. diff --git a/docs/COPILOT_PROJECT_NATIVE_INTEGRATION_LINT_PLAN.md b/docs/COPILOT_PROJECT_NATIVE_INTEGRATION_LINT_PLAN.md new file mode 100644 index 000000000..a276a4c2d --- /dev/null +++ b/docs/COPILOT_PROJECT_NATIVE_INTEGRATION_LINT_PLAN.md @@ -0,0 +1,134 @@ +# Copilot and Gemini: nine integration lint corrections + +## Evidence and exact source boundary + +This is a review proposal, not an implementation or a qualification result. +Root's combined integration is commit +`d1b1f51c98ffd0142993456b51762f7331aed6b7`, tree +`7906245dd8cb1287ebd78dd13b300aec99091fe3`, based on current main +`bd205dda` and the active project program. Root's actual full-delta all-enabled +lint against main reports exactly nine findings in +`/tmp/uap-active-nine-integration-lint.log`. Integration Go contracts passed +in 5.273s and 216 Python contracts passed in 31.782s before this proposal. + +The authoritative leaves are Copilot PR527 +`9b8ddc5332d70ca0c8d39c41c5ce60f3bba1c6e7`, tree +`8386a313607a2d1acfd5583bd9335d9ce7af1340`, and Gemini PR526 +`fa7b9db9a94e39392934be5b3820f6266900c13b`, tree +`0310327c0dc9ec64036b99bb99387bdecf750cbc`. Their relevant source files are +byte-identical in the combined integration. Their new genuine native captures +are still pending; preserve those source identities and wait for their raw +evidence before applying or publishing a follow-up to either leaf. + +## Exact changes + +| Client and existing file | Actual finding | Proposed correction | +| --- | --- | --- | +| Copilot provider, message validator | gocritic argument-order heuristic at the role membership expression | Name the exact existing delimiter string as a local constant and keep the same `strings.Contains(collection, token)` call and refusal. | +| Copilot provider, message validator | staticcheck De Morgan expression | Replace the negated assistant-and-calls term with its exact equivalent `role != "assistant" || !hasCalls`, preserving the surrounding missing/null-content condition. | +| Copilot provider, `start` | noctx `net.Listen` | Change only this private method to `start(ctx context.Context)` and use `(&net.ListenConfig{}).Listen(ctx, "tcp4", "127.0.0.1:0")`. | +| Copilot contract, existing JSON controls | gofmt at the hostile JSON table | Apply ordinary gofmt; retain all cases, order, bytes and assertions. | +| Copilot contract, hard-link refusal diagnostic | misspell `hardlinked` | Use the plain diagnostic `immutable file with multiple links accepted`; keep the actual link/refusal test unchanged. | +| Copilot contract, provider request authoring | noctx `httptest.NewRequest` | Use Go 1.22-compatible `http.NewRequestWithContext(context.Background(), ...)`, check its error with `t.Fatal`, and retain the exact request target as `RequestURI`. | +| Gemini contract, native stream role branch | staticcheck tagged switch | Convert only the existing user/assistant/default if-chain to `switch row["role"]`, with identical stage checks, assignments, returns and default refusal. | +| Gemini contract, provider request authoring | noctx `httptest.NewRequest` | Use the same Go 1.22-compatible context-aware request construction, checked error and exact `RequestURI` preservation. | +| Gemini provider, `start` | noctx `net.Listen` | Apply the same private context parameter and `ListenConfig.Listen` change as Copilot. | + +Each provider has exactly one actual `start` caller, in its existing +`agentplugins__project_native_attempt_test.go`. Pass that fixture's +already-held `f.ctx` from the caller. This adds the two caller files to the +four finding files; do not add a provider context field, alter constructors, +or add a fresh deadline. Gemini's complete-cycle provider already uses its +held context and is not part of this change. + +The authoritative leaves still declare Go 1.22 even though current main uses +a later Go version. Do not use `httptest.NewRequestWithContext`, a newer API. +The replacement retains method, absolute URL/route/query, body, header and +host mutations, response-recorder path and direct handler invocation. Retain +`RequestURI` as the original absolute target to preserve the incoming-test +request shape. No request is sent to a real service by these controls. + +The role warning is a false-positive argument-order heuristic, not evidence +that the arguments should be reversed. Naming the existing collection makes +the intent explicit without changing the accepted input set. The primary +go-critic rule in `checkers/rules/rules.go`, Git blob +`f7bdf35aed2f539428de7359d477f43de856ab68`, expressly exempts a named first +argument. Preserve the original membership behavior; do not fold a distinct +role grammar change into this lint correction. + +## Preserved authority and behavior + +Keep listener address/family, provider routes, body bounds, exact credentials, +HTTP timeouts, ordinary server close, request/response counts and one-call +ordering unchanged. Using the fixture's existing context only binds listener +creation to its original work budget; it does not replace provider shutdown +or process/cgroup supervision. + +Keep all source and executable pins, independently authored installed files, +the held firstLaunchAt/original-config digest, Gemini trust/settings/policy, +native argv/environment, package/data/receipt authority, permission and +approval checks, privacy/redaction and artifact admission unchanged. The +original work/total deadlines and fatal cleanup checks remain mandatory. + +Copilot remains its deliberately failed native-grammar review capture, with +all five qualification/authentication/real-model flags false. Gemini remains +its deliberately failed complete-cycle first capture, with the same false +flags and separate future completion requirement. Do not promote historical +or newly pending artifacts as a consequence of these lint corrections. + +Scope is the two existing provider files, two existing contract files, two +existing legacy-attempt caller files, and a truthful plan/validation record +per authoritative leaf. No shared Python/Go helpers, workflows, selectors, +production adapters or VS Code-specific files change. + +## Review, validation and publication + +Obtain root R1 and independent Kimi-owner R2 against this exact proposal +before implementation. Review actual new native artifacts first and reconcile +the exact current leaf heads. Preserve any separately required raw-evidence +fix as its own reviewed change; do not silently expand this plan. + +After the two plan approvals, apply the small changes in isolated worktrees +from the authoritative current leaves. Obtain independent exact-code review. +Use one coordinated exclusive Go/lint slot for the existing focused Copilot +and Gemini contracts, gofmt/diff checks, all-enabled affected lint and the +unchanged unfiltered whole-file architecture/size lint. Root should also +rerun the actual integration full-delta lint against main to close all nine +reported findings. Do not add mechanical mirror tests or rerun vendor clients +locally. A lint or compiler failure remains a failure to resolve, not a reason +to add suppressions or change toolchain declarations. + +Root alone publishes each frozen reviewed leaf after a fresh non-forced +expected-head check, then reintegrates it. Preserve the current pending run's +source/evidence identity. Native observations from an older head are not +retroactively relabeled as results of these later source changes. + +## Accepted implementation record (2026-10-27) + +Root R1 and independent Kimi-owner R2 approved the exact proposal SHA256 +`33cf3a7e9400e451b0ced924c71029fdaf2c21efb2110618489bf3aaafddd6a4` +before edits. The genuine source-bound runtime 40553325878 has now completed and +its current native/frontend artifacts were independently reviewed before this +follow-up. Historical observations retain their original source identities. + +This commit applies only the three existing Copilot Go files named in +the proposal. Evidence-driven changes are separate commits with their own +accepted plans. Validation results are recorded after the required gates. + +### Additional current-leaf finding + +The isolated Copilot leaf exposed an existing unparam warning on the shared +mode-preserving writer: all its reachable callers used0600, whereas the +combined active-nine integration also contained real0700 callers. Root R1 and +independent native-CLI R2 separately approved changing only the existing +HeldReadsRejectAliasesAndHardlinks test's ordinary immutable fixture from +0600 to0700. This represents its actual immutable executable permission shape; +the file is never executed. Bytes, digest, symlink and hard-link refusals remain +unchanged. No shared parameter, suppression, dummy reference or product rule +changes. The existing hostile JSON table receives gofmt simplification too. + +Focused inert Copilot contracts pass with the separately authored readiness +contracts present. Final affected and whole-root lint results are recorded in +the readiness validation record after the gates. No vendor or public installer +executable was run locally. Historical source9b8d evidence remains failed and +all five qualifications remain false. diff --git a/docs/GEMINI_PROJECT_NATIVE_ASSESSMENT_CACHE_CLOSURE_PLAN.md b/docs/GEMINI_PROJECT_NATIVE_ASSESSMENT_CACHE_CLOSURE_PLAN.md new file mode 100644 index 000000000..63cc67257 --- /dev/null +++ b/docs/GEMINI_PROJECT_NATIVE_ASSESSMENT_CACHE_CLOSURE_PLAN.md @@ -0,0 +1,196 @@ +# Gemini: exact source-bound security assessment cache closure + +Accepted plan: root R1 and independent native-finish R2 reviewed exact draft +SHA256 c310ebb04ea20da87d3cc0073a703b0f0043d18ee469c881e7fcf977bdcc4328 +before implementation. The published source being corrected is c0b25d933b35ed1d0172f09b8a81f957d69727ac, +tree9b93ec3d0e49822e6f01b100e8ba41934502e6e7. This is a fixture authority +correction, not a scanner, installer, qualification or release change. + +## Fresh genuine evidence + +Run40569317705/job122427178730 failed after13.507s at add-user. The actual +public command exits0/error=false/context=false in369ms. All3 baseline +catalogs and the4-frame empty baseline-a native session succeed. One provider +exchange advertises no owned declaration; all4 probe segments contain zero +actual probe events. The fatal remains Gemini public mutation escaped exact +state closure; this is not the deliberate final review barrier. + +Native12765464677 is72812B, outerSHA256 +5a9692eff8f757210fecbc184b9ca91b79abbe219c77bc6a1a8ac1f0f0e6cc54, +innereda79fa50d1e5c1b6ebbab1d36248600cdc2a276bfd789fd53e6a50298a264d0, +24 closed ordinary members. Frontend12766166734 is53591B, outer + d6cb5f1d5b26409279e2c38019a601ff1f20ee859ce9e5903991893940726f75, +inner0802df528dff9af52245c64a68cd74bcc9bf230bf2756b55bb7a0a92a5c67874, +25 members. Exact source/tree/committed/empty patches and clean build frames, +all24 frontend and30 nested raw byte/hash joins, command receipts, baseline +session/provider facts and current failed-only admission pass independent +review. Audit /tmp/uap-gemini-c0b-current-40569317705/independent-current-raw-audit.json +has SHA25669251538fde00c340393c544c917844107f17d77d20f880dc906e595036e9871. +The failed entry/path/tree was not exported. This plan does not claim a measured +refused filename. Full provider-stage closure remains incomplete and must not +be promoted. All five/runtime-complete/observed/account/model flags stay false. + +## Exact source proof + +cli/cmd/agentplugins/compose.go configures both the global cache root and user +state root from AGENTPLUGINS_HOME. The fixture sets that to installer-state +and freezes it before public operations. nativeProvisionScanner creates only +the pinned scanner binary subtree under security/lintai. The ordinary CLI +SecurityEvaluator uses FileCache{Root:globalRoot/security/assessments} for both +user and project operations; project state .uap is separate from that global +cache. SourceAcquirer also creates/removes snapshots in the global root. + +The captured add-user security object has evidence_source=local_scan, the held +source/manifest subject, lintai0.1.3/default policy, no_blocking_findings, +zero counts, scanned_files3 and report_digest90f5acb6ff3ac64f669be4f4ba6deea7ae5aa3a9954662441c0e5498b8d56598. +Evaluator.Evaluate must successfully call Cache.Store before returning a local +scan: cache errors propagate and would fail the command. FileCache.Store creates +the0700 assessment parent, writes0600 JSON through a temporary file, syncs and +closes it, and atomically replaces exactly CacheKey+'.json'. Cached Evidence is +empty, with empty Findings omitted; successful cleanup leaves no temp residue. + +CacheKey hashes the NUL-joined held tree/manifest digests, scanner ID/version, +policy ID/version/digest. For this actual held U-one subject the source-derived +relative filename is security/assessments/b99b8ba443fb9059fc6b82486fc8e78537380cc18512785cf689dfc0673ca8a2.json. +It is a source-derived output, not an exported path observation. The current +state closure permits neither its new parent/leaf nor changed metadata on the +existing security parent. This is another independently proved omission after +the separate installer-tmp correction. Direct Loader/Stager/Kernel contracts +bypass CLI SecurityEvaluator, explaining the missing file-cache seam. + +## Exact authority and lifecycle correction + +Add a bounded client-specific cache-frame helper/ledger, wired only into the +existing Gemini public proof path. It owns no filesystem writes. Expected +assessment bytes and keys come from the independently held selected recipe, +not incoming paths, hashes, cache JSON or a new observed baseline. + +Use the fixture-pinned current security requirement: lintai0.1.3, policy +agent-plugin-install/version2/digest9cf869e299d847d7078aeca01f5a182fcdb0144bbf513c83290459991c79e037. +For the known harmless source shape require schema1, selected recipe tree and +manifest digests, no_blocking_findings, zero counts, scanned_files3, the exact +known report digest above, no findings and no stored evidence_source. Rebuild +the exact domain JSON serialization and require whole-file size/hash/bytes +closure; unknown fields, trailing data, wrong types, policy/source/scanner/ +report/count/evidence changes all refuse. This observes the cache output; it +does not authorize installation from a fixture-supplied security verdict. +The actual public scanner/evaluator/CLI policy path remains mandatory. + +Only finite source-acquisition operations may introduce the one current +source-bound cache entry: add-user/add-a/add-b, repeat-add-a, unchanged-update-a, +intact-repair-a, update-a and missing-repair-a. Select scope/recipe from the +existing fixed label table. Cache hit preserves the exact earlier entry +including inode/owner/mode/content; no same-byte replacement or rewrite is +accepted. The ledger retains prior U/A/B/A-two entries, maximum4. A-two authority +comes only from the existing separately verified intentional source revision. +A source operation may add only its exact current key, never another scope's +or arbitrary digest key. Removal and negative repeated removal allow no new +entry or cache mutation. Native/listing stages keep the complete frozen maps. + +The exact security and security/assessments directories, when present, must +be ordinary0700 and retain existing device/inode/UID/GID/mode identity. Validate +these and all expected/unknown assessment children BEFORE any unchanged fast +path. Unknown children, directories, aliases, special/multiple-link files, +assessment temporary residue, deletion, replacement and body/mode drift refuse, +even if an unexpected entry is unchanged in both maps. The scanner binary tree +and every other global state/payload/data/caller entry remain frozen exactly. +Legacy inert Stager-only paths whose cache is absent need no invented scanner +or cache. Actual public source-operation wiring requires the expected entry; +there is no runtime opt-out, environment switch or success fallback. + +For project operations, snapshot the complete global user-state root alongside +the selected state/profile/cwd. Validate the exact cache delta and require all +other global state/scanner/payload/data/caller records unchanged. The global +root directory may retain identity/owner/mode while its bookkeeping metadata +changes during a permitted source operation: the real SourceAcquirer creates +and removes snapshots directly there. This exact directory identity check is +not an unknown-child allowance; every residual child still belongs to the +full inventory and must be proved or refused. Outside those finite operations, +the existing full-record freeze remains. User operations retain the existing +selected payload/data/state closure in that same global root. + +After cache-frame validation, project out ONLY the individually validated +cache records/parents when applying the existing selected state closure; no +security-prefix bypass or broad open/global root exception is allowed. For a +project operation the remaining global map must match its prior frame (apart +from the explicitly checked root-directory bookkeeping). Preserve all existing +selected source, binding, payload, config, ownership, data, state and cwd checks. +Recapture every complete involved tree and require stability, then atomically +advance the frozen maps and cache ledger from those same verified captures. +No cache or global baseline is adopted before all proof checks complete. + +No raw artifact schema/mode, Python success admission, provider, argv, source/ +executable/scanner pin, trust/permission, host/process, work/total deadline, +production code or VS Code changes are included. Existing raw public security +receipts remain captured; live cache-file equality is source-attested by the +reviewed Go proof, just like the existing full on-disk preservation frames. + +## Meaningful inert verification + +Exercise the actual production FileCache.Store with an independently authored +finite domain assessment and verify exact key/JSON/mode/temp cleanup using real +held ordinary captures. This is a file-format/authority contract, not a fake +scanner execution or an authorization to skip native security. Pin independent +known key/byte/hash values as the primary contract, with actual Store parity +as supplementary evidence. Do not launch any installer/vendor/scanner locally. + +Test new and retained valid entries, all4 ledger identities, current-source +selection, cache-hit identity preservation and project-global cache addition +while user receipt/data/scanner/caller bytes remain fixed. Refuse changed or +unchanged unknown entries, wrong source/manifest/scanner/policy/report/count/ +evidence/type/unknown/trailing fields, mode, hardlink/symlink/specials, temp +residue, deleted/replaced entries/parents, caller/scanner drift, wrong scope/ +label and original-context exhaustion. Demonstrate that a rejected frame never +updates the accepted ledger or frozen maps. Use actual ordinary files/tree +captures, not fabricated stat maps or positive hosted guards. Existing user/A/B +actual Stager/Store/native-file contracts remain required and cache-absent +inert paths remain valid without inventing a scanner result. + +Before source edits obtain root R1 and an independent R2 on this exact plan. +Then implement in an isolated current-head branch and obtain exact-code review. +Coordinate the exclusive Go/lint slot for meaningful Gemini/shared contracts, +current Python admission/raw replay, actual all-enabled affected root lint and +unchanged whole-root architecture/size lint; check full branch whitespace. +Root alone publishes after fresh-head reconciliation. A new genuine cycle is +required to establish later stages. Both historical failed captures remain +failed/allfalse; another observed discrepancy is reviewed separately. + +## Implementation and local validation, 2026-10-27 + +The correction is isolated on exact c0b25d9, which already includes program base +a412ba5e. Only the Gemini lifecycle fixture and its inert contracts change. +The public apply seam derives an expected descriptor only for the eight finite +source operations. The shared proof captures the global user state root, validates +the finite cache ledger, applies the existing selected state proof to its exact +projection, recaptures all complete trees, then advances accepted frames. +Cache-absent direct Stager contracts retain their original path. + +The independent fixed key/578-byte JSON/SHA golden and actual production +FileCache.Store/Load parity pass. Real-file contracts cover all four source +identities, cache-hit identity preservation, project proof retaining actual +user state, finite labels and recipes, descriptor bounds and cloning, unknown +entries including unchanged entries, wrong modes, replacement/deletion, alias/ +hardlink/FIFO, temp residue, malformed whole JSON, source/security drift, +unrelated caller/scanner drift and original-context cancellation. Rejection +preserves the incoming ledger and captured maps. These are file-format and +proof contracts; no vendor, scanner or public installer executes locally. + +Observed gates on the source submitted for independent code review: + +- Focused `go test ./repotests -run '^Test(Gemini|ProjectNativeRuntime)' -count=1`: PASS, 1.724s after the ordering correction. +- Existing Gemini and runtime Python admission contracts: 62 PASS, 8.387s. +- The retained current c0b native ZIP replays through the unchanged reader as + its genuine 24-member failed/all-false capture; no historical qualification changes. +- Actual all-enabled full-root affected lint against a412ba5e: zero issues. +- Unfiltered whole-root revive/funlen/gocyclo/gocognit/dupl/depguard gate: zero issues. + +The first lint invocation lacked the pinned Go directory in PATH and did not +analyze source. After PATH correction, the first analyzed run identified three +tagged-switch style findings in new inert refusal controls; they were corrected +and both final gates pass without exclusions. Self-review also identified that the pre-existing native settings-lock validation +followed the old frozen-map advancement point. Root required that unchanged +mode/size/hash validation to run before final full recapture and any frozen-map +or cache-ledger advancement. The corrected proof validates it there and later +assigns protected/file frames from that already held record. Source publication +remains root owned and requires final exact-code review. A fresh genuine native capture remains +necessary; the unexported refused path and later lifecycle remain unproved. diff --git a/docs/GEMINI_PROJECT_NATIVE_COMPLETE_CYCLE_FIRST_CAPTURE_PLAN.md b/docs/GEMINI_PROJECT_NATIVE_COMPLETE_CYCLE_FIRST_CAPTURE_PLAN.md new file mode 100644 index 000000000..3cb00cd94 --- /dev/null +++ b/docs/GEMINI_PROJECT_NATIVE_COMPLETE_CYCLE_FIRST_CAPTURE_PLAN.md @@ -0,0 +1,827 @@ +# Gemini: complete user/A/B lifecycle first capture + +## Proven baseline and honest first-capture boundary + +Base is published PR526 `2ff752a5909c96333786cfe80454fd8bf7be3a3b`, tree +`9a98d09f6ec25d3d22b137309035bf213f284839`. Preserve all reviewed research, +provider signature/wire-ID, explicit environment and exact stderr changes. +Do not modify the already published source slice to incorporate another +client's fixes or current-main integration. Root owns that integration. + +Genuine runtime40493698035/job122162956524 and research40493697693/ +job122163247836 both passed on this exact source. Native artifact12732555875 +has21 closed ordinary members (outer SHA256 +`35d0bf0302152d05589c6b7d0a0de7410f319978913355988f4ee6ff3a23e81b`, +inner `4425a8ed6fc9e22855a6f0b0f1b9cd3c6ff128ba7abe39ca90d17700013fb0e4`); +frontend12732655592 has25 (outer +`bb7ba91b03a3e0fdd12ca72891845ade55d28aae950aa4eb1bf47794c7f37d71`, +inner `41d1b5b27d54fa9cf8fe2fe67288e8029a810fe70a30e88b06f2f25eda0ec02b`). +Research12731818953 has51 (outer +`f1ee45433de6f4521209e4329497319b0488ae09bf093968294e264ea03c5151`, +inner `ca080f34aac3d5072b13b57f679f8a7f4648ba9e13497a9265010f99f3bf110b`). +All API outer digests, canonical unique ordinary ZIP members/CRCs, exact +source/tree/clean records and74 frontend/research stream joins were checked. +Independent native six-frame/two-HTTP/three-probe-event facts and distinct +native versus wire call-ID joins passed. Native exit0/clean process and +attempt_complete=true, research collection_complete=true/error=null are +observed. All five broader qualification flags remain false in both artifacts. +Audit `/tmp/uap-shell-fresh-oct27/gemini2ff-source-stream-audit.json`, SHA256 +`44ebda9c3fd52cbedd5e401efa486b547576bc6ca8bc530cb82135ecb830bda0`. + +This slice builds the full lifecycle capture on that positive single-tool +baseline. The first complete cycle deliberately fails its final review gate, +retaining all qualification/runtime-complete/authentication/model flags false. +An observed first capture never qualifies by changing its summary after the +fact. A separate reviewed grammar/qualification amendment and fresh genuine +successful cycle are required later. Unknown output or process behavior +remains a captured failure, not a compatibility allowance. + +## Supported source and ownership model + +Use actual public add/update/repair/remove, three independent same-named +portable packages and current typed state receipts. In `clients/gemini/scope.go` +the project registry is selected project/.gemini; the user profile remains +original HOME/.gemini. Shared managed payload/data are scoped to the user +installer-state root or each project's .uap root. User native-config activation +is Active/Installed through the current shared completion helper; project +`geminiProjectStatus` deliberately reports Prepared/Installed and no attestation. +Native proof does not rewrite those receipt statuses or claim vendor login. + +Each package contains one skill and one selected stdio MCP server, so actual +`packageNeedsPluginData`/group staging requires one owned data receipt in +all three scopes. Independently verify current `domain.StateSchemaVersion`, +duplicate/unknown-free full typed state, single installation/client, exact +source binding/package inventory/revision, stable installation/client/physical/ +data IDs, native profile root, exact object IDs/kinds/paths/source-relative +names/digests/protection, launcher/metadata and all installed payload bytes. +No blank data-token shortcut, Store.Load migration, receipt-derived source +recipe or unchecked extra receipt is allowed. The kind names +gemini_global_mcp_server and gemini_global_skill_directory are used in both +scopes; their held paths, scope and independent receipt identity decide authority. + +Default removal leaves no clients and DataRetained=true with the same owned +data receipt/marker/payload, as source `finalizeLastBindingState` requires. +Repeated removal is the exact missing selected-binding refusal from the public +CLI: normalized natural exit1/error=nil/empty stdout and exact source-derived +stderr, no context/capture/cleanup error. It must preserve retained state, +data, foreign entries and user/B byte-for-byte. Do not invent no_change JSON +for that outcome or use a plain exec path to recover raw ExitError. + +## Source-pinned native request boundary + +Keep Gemini CLI0.65.0 bundle/Node24.21.0 and all complete immutable member +hashes, scanner/source/runtime identity, genuine outer hosted guard, closed +environment and provider route/auth/body bounds unchanged. Native runs only +on genuine opted-in GitHub-hosted Linux amd64; no local client/installer. + +At Gemini source6006c14a4decfe4b891c6263ad6ad5992e404b5b, +core/client.ts blob01bcc1e19388c14ae3b310b50daa58d4791b28dc (SHA256 +e25cd763ebc63944f3cf5178ca6c0d9c828634f57e921a98e52c2cb91276fe63) +sets exactly one tools group containing getFunctionDeclarations(), even +when empty. core/geminiChat.ts blob095a5292c4820c8158bbb73c5af97d729e69bd87 +(SHA2567aeca2fc0eff93f003c8d628889cf6941f9359597673c907fb64d049fadd3945) +forwards that group. tool-registry.ts blob75e8e6cdfcaec75a919a2791e56993cf84aece38 +(SHA256172906fe3caa29e71d5accd04b9e94e16a52c799dcf88b1f12e690835f24f5c0) +builds a unique active-tool declaration array with qualified MCP names. +SDK38cac5bbf4941ec5fa760238bd423c0ecc2c6f04 converters blob +509660270e9cfe2173850ba0a8e9e4ddbeb3b3af (SHA256 +2b9d05d70130bbb8c0bfdfd7bf68d7e909892d45df3baa64f0ee212dec0ec317) +and _transformers.ts blob5f1ab95de17a695e6d0e643bd1b13017ae1f03ac +(SHA256bb58569df80d6e9662f1f2a26b5e36fbd619c04f4dabaaa69e927558f1b4482a) +preserve that group and its empty declaration array. Full files/hash checks +are retained at `/tmp/uap-gemini-lifecycle-pinned-source`. + +The cycle-only request validator therefore requires one exact tools group +and an exact closed set of zero, one or two independently selected fixture +declarations. Empty is exactly [{functionDeclarations:[]}], not omission, +null, an empty tools array or interchangeable shapes. Validate every nonempty +declaration with the existing strict schema/wait_for_previous rules, exact +name and authored description. Reject foreign/builtin/duplicate tools. Keep +the existing single-attempt request validator/default behavior unchanged. +All other request content/generation/signature/role/security fields retain +the current strict rules. If the actual native empty/group framing differs, +the first capture fails rather than expanding its grammar. + +One held listener owns all stages, with a mutex-protected finite arm/complete +table and no re-arm while requests/handlers/native children remain open. +Use six calling stages with two HTTP requests each and four no-call stages +with one each, maximum16 total. The response issues only the preselected +inspect_runtime call; unknown or cross-stage request/order/call history fails +and cancels. Empty stages issue only their exact sentinel text and never a +tool response. Keep separately constructed exact native ID and HTTP wire ID, +thoughtSignature and untrusted-context output wrapper; never normalize incoming +identifiers or accept either identity interchangeably. Every native session +gets a fresh stage-specific call ID/sentinel; each installed component retains +its original authored nonce/env/source bytes across all sessions. + +## Disposable fixture and controlled mutation authority + +Use original independent HOME/TMP/XDG, distinct Git A/B and outside user cwd +(initialize all three Git roots). Author U/A/B independent sources named +uap-gemini-cycle with skills/MCP names uapgeminiu/uapgeminia/uapgeminib, +fixed scope nonces, U-one/A-one/B-one recipes and a later A-two revision. +Freeze each source before any public install; only the exact A source revision +step may replace its authored bytes, with all other sources held unchanged. + +Author only the supported original settings/auth-selectedType/telemetry/ +updater/experimental values from the existing fixture, exact A/B/outside +TRUST_FOLDER entries and deny-all tool policy plus exactly three fixture +inspect_runtime allow rules. No broad approval, bypass mode, inherited key, +account credential, trust dialog workaround or egress claim. Preserve existing +research untrusted-folder proof separately. Seed harmless disabled/excluded +foreign MCP members and disabled foreign skill files at user/A/B paths; +these remain complete value/key/body authority, not tool inputs. + +Public user add/remove intentionally changes its one owned mcpServers key +in original settings.json. Permit that selected mutation only during its +authorized public command. Independently verify the complete expected object +including all original auth/trust/privacy/experimental/updater keys, exact +foreign members and key membership before freezing its resulting bytes. +Never simply remove original settings from protection or adopt unchecked +observed JSON. During every project operation/native command, freeze that +entire user config and all other user/sibling owned config/skill/state/payload/ +data/receipt/caller files. Apply the same exact-object rule to the selected +project settings. Keep ordinary no-follow bounded reads/identity/checked-close +mechanics and explicit absence guards; no new blanket native-profile waiver. + +Only registered public operations open their exact state/transaction/managed/ +data/native-object closure. Only a selected native call may append its known +probe log or create/read its exact nonce marker. Freeze data/ownership marker +and caller files before every native run; require selected marker delta only, +no sibling/user data mutation. Every advertised owned server may initialize +and list once in a fresh process; only the selected caller may tools/call. +Collect append-only per-component event segments with fresh PID/session, +same installed nonce, native interval and exact initialized/listed/called +facts. Removed/unselected servers must produce no event. An unselected user +server may initialize/list in A/B, but never call or mutate its retained data. + +For repair, prove the independent current owned A skill NativeObject first, +then remove only its checked SKILL.md and exact now-empty owned directory +with nonrecursive os.Remove, checking held identity/final absence. This +matches verifyGeminiSkill's allowMissing directory boundary. A missing leaf +with an existing altered directory, extra file, alias or wrong owner remains +tampering, never an accepted repair fault. No recursive removal/adoption. + +## Finite operation and observation matrices + +The public command table has exactly16 commands: git-a/git-b/git-user, +version, then the following twelve scope operations. Use explicit user scope +or exact project --scope project/--project-root, --target gemini, --format json; +adds include --no-save. Verify strict installer JSON and exact source-derived +progress and mutation/no-change behavior; repeat removal has the exact separate +exit1 refusal above. Do not broaden the shared command matcher. + +| Public operation | Scope | Independent expected effect | +| --- | --- | --- | +| add-user |U|U-one skill/MCP/data, outside discovery onlyU| +| add-a |A|A-one; originalU preserved| +| add-b |B|B-one; originalU/A preserved| +| repeat-add-a |A|no change; exact source/state/native/data bytes stable| +| unchanged-update-a |A|no change; exact identities/revision stable| +| intact-repair-a |A|public repair; same revision/IDs/data/native recipe| +| update-a |A|authored A-two; stable installation/binding/physical/data IDs| +| missing-repair-a |A|restore exact absent owned A-two skill directory| +| remove-a |A|A native/payload absent; retainedA data andU/B intact| +| repeat-remove-a |A|exact absent-binding refusal; all retained bytes stable| +| remove-b |B|B absent; retainedB data andU intact| +| remove-user |U|U absent; retainedU/A/B data andforeign authority intact| + +Run14 native `skills list --all` observations in fixed order: baseline-a, +baseline-b, baseline-user, installed-user, installed-a, installed-b, +repeat-add-a, unchanged-update-a, intact-repair-a, updated-a, repaired-a, +removed-a, removed-b, removed-user. Baseline has no owned rows; authored disabled foreign +rows and the exact pinned built-in rows remain. User seesU, A seesU+A, B seesU+B, removedA/B seeU, finaloutside sees no +owned skill. Verify native exact path/enabled/nonbuiltin/description against +independent source recipes plus each original foreign row; reject sibling, +missing, foreign or stale revision. Read exact installed SKILL.md bytes too. +Do not claim native prompt-body activation merely from catalog description; +the built-in skill activation tool remains denied by policy. + +The already closed2ff research configured-a-skills stdout also contains the +two native built-ins `antigravity-support` and `skill-creator`; this is not a +new full-cycle grammar observation. Preserve those two exact enabled/builtin +rows, independent names/descriptions and paths under held client/builtin, +with no other builtin or unknown catalog row admitted. Independently read the +full pinned6006c14 files: antigravity-support SKILL.md git blob +`a209de7a801138187caf982ed81afe6b5507d7c0`, SHA256 +`2b866bce962f642be8c0dd74ffc2548fa29f2100bc945518b2f738b7d7d6fd38`; +skill-creator SKILL.md git blob`d85afc668a24b3a3c7a16f912947a0304fa21745`, +SHA256`aab93935325978cb5a54b4907ae1ca11d7b4a903925ed0cc1739345392280db9`. +These exact whole-file hashes are also already present in the actual2ff +acquisition/runtime identity; retain and revalidate them before native catalog +comparison. A builtin never counts as a fixture skill, exposed provider tool, +activation result or additional authority. Add exact-name/path/description/ +builtin/enabled and extra/missing builtin hostile catalog controls. All owned, +foreign, raw output and deny-all tool policy checks above remain unchanged. + +| Fresh native session, in sequence | Cwd | Advertised owned MCP / selected action | +| --- | --- | --- | +| baseline-a |A|none / sentinel only| +| installed-user |outside|U / U-one write marker| +| installed-a |A|U+A / A-one write marker| +| installed-b |B|U+B / B-one write marker| +| restarted-a |A|U+A / A-one read same retained marker| +| updated-a |A|U+A / A-two read same retained marker| +| repaired-a |A|U+A / A-two read same retained marker| +| removed-a |A|U / sentinel only, noA events/call| +| removed-b |B|U / sentinel only, noB events/call| +| removed-user |outside|none / sentinel only| + +Interleave observations immediately after their corresponding public effect; +run restarted-a after intact-repair-a, before editing A source. All fresh +processes use exact existing default approval/output/model argv and original +HOME, with only held fake loopback provider secret/base URL. No direct probe +invocation can stand in for native startup. Preserve current exact whole stderr +tuples only after clean process capture; unknown diagnostics/API/auth/cleanup +errors remain fatal. Source-guided empty native stream is first-capture-only +until actual raw review; no guessed empty success qualification is introduced. + +## Bounds, closed evidence and final review gate + +Preserve original150-second work origin,180-second final bound, ordinary OS +descendant supervision/5-second grace,80 members,2MiB/member and16MiB total. +Do not renew a stage or cleanup deadline. Public/Git/version deadlines are +30seconds, listing10seconds and native sessions60seconds, each bounded by +the original context. If40 total operations cannot finish inside that budget, +retain the exact failing prefix; do not increase budgets as part of this plan. + +Keep16 public raw triples (48 members), runtime-attempt.json and exactly8 +bounded aggregates: cycle-native-commands.jsonl, cycle-native-events.jsonl, +cycle-discovery.jsonl, cycle-provider-requests.jsonl, cycle-provider-responses.jsonl, +cycle-provider-receipts.jsonl, cycle-probe-events.jsonl and cycle-proof.jsonl. +Maximum57 members, still below80. Each aggregate<=1MiB, fixed registered stage +and component labels, raw byte count/SHA256/base64 joins; no dynamic ZIP names, +truncation, omitted response or optional stage can count as complete. Actual +single-attempt requests were approximately27/28KiB, making the16-request bound +plausible, not guaranteed. Aggregate overflow is a retained failure. + +The proof aggregate contains the four frozen source recipe inventories +(U-one/A-one/B-one/A-two), all twelve public post-state proofs, and pre-revision/ +pre-fault authority proofs. Freeze stage order and exact counts independently +in Go/Python. No executable/profile credential bytes are exported. Validate +strict JSON/JSONL and semantic nested JSON strings before base64 persistence +and after Python decoding, with the already reviewed whole-member4x parse-work, +16384nodes/depth64 and strict32 document depth/key4096 limits. Complete-number +preflight distinguishes ordinary invalid numeric-prefix text from actual +nonfinite JSON; bound/UTF8/parser-resource failures refuse. Plant private +canaries in nested strings/keys/JSONL and all aggregate streams. Preserve +raw bytes except the existing exact held fake-secret redaction; do not +replace JSON/path/argument fields or merge stdout and stderr to fit a parser. + +New selected test is TestAgentpluginsGeminiNativeProjectCompleteCycle, using +the existing Gemini hosted phase/opt-in/timeout/acquisition. Point only that +client's existing CASES test/file to it. Preserve old single-attempt source, +tests and21-member failed/successful admission for historical source-bound +evidence. No new workflow/job/opt-in/public PR/release. + +Cycle mode is gemini-complete-cycle-first-capture. Defer its finalization +immediately after the genuine constructor returns. Every failed prefix retains +all complete raw triples/aggregates, exact completed-stage prefixes and a +truthful failed/incomplete/allfalse envelope. All10 native stages and provider +handlers must be ordinarily closed, all matrices/live authority/privacy/total +checks complete, then set only cycle_observed_complete=true and deliberately +fail at complete-cycle-capture-review. Late cleanup/privacy/serialization +failure keeps that observation false or explicitly failed; it never upgrades +runtime_attempt_complete or any qualification. Outer frontend still requires +real selected-test pass and ordinary delegated/process closure for any future +qualification. New Python mode rejects source/tree drift, unknown labels, +orphan triples, count/order/hash/type/proof/flags contradictions and arbitrary +promotion; current single-attempt admission stays distinct. + +## Scope and required verification + +Source scope is new bounded client-specific Gemini cycle Go fixture/source/ +state/data/native/provider/artifact/contract files, the existing Gemini test +wrapper only as required for selecting the new test, existing Python runtime +case/mode dispatcher with a bounded Gemini cycle admission/contracts module, +and this plan/validation record. No production adapter/shared process/native +host/pin/source-acquisition/research collector/portable engine/VS Code change. + +Before editing obtain two independent plan reviews. Inert contracts must use +real Loader/Planner/Stager/Gemini adapter/current Store.Save for both scopes, +independently authored source/complete payload/data/foreign proofs, missing +directory repair positive and partial/tamper refusal. Exercise wrong roots/ +revision/receipt IDs/extra receipts/unknown state, source mutation, complete +user original-settings membership, sibling/foreign/data/marker preservation, +held provider stage/identity/call-order, exact empty/1/2 declarations and all +hostile signature/native-versus-wire/tool/action cases. Replay actual2ff +native requests/six frames/three probe events through the current strict path; +empty/full-cycle synthetic controls remain inert, never hosted execution. +Test exact complete57-member and failed-prefix envelopes and every late +cleanup/deadline/flag/source/privacy contradiction. No test may mock a hosted +guard positive or run a vendor locally. + +Obtain two exact-code reviews, actual focused Gemini/shared Go and Python +contracts, affected all-enabled and whole-file architecture/size lint in an +explicit exclusive slot, formatting/AST/diff checks. Root alone publishes +the frozen plan/code on existing PR526 after fresh-head reconciliation. Audit +the new genuine full-cycle raw before proposing any separate completion +amendment. All account authentication and real-model qualification remain +false throughout scripted-provider proof. + +### Local inert supervisor capability control + +The new inert fixed `/bin/sh` natural-exit control encountered the existing +typed `process.ErrOrdinaryContainmentUnsupported` prerequisite refusal in this +local container (a live `/proc/PID/task/TID/children` interface is unavailable). +As in the separately reviewed Cline control, only that exact `errors.Is` +sentinel may skip this local OS primitive test; it is never counted as a passed +native or containment proof. All pure exact-exit/hostile outcome controls run +unconditionally in a separate test. Every actual hosted cycle still uses the +unchanged full-descendant supervisor and treats missing containment, cleanup, +context and capture failures as fatal. No new capability fallback, alternate +runner, hosted marker or real-runtime skip is authorized. + + +## Accepted finite complete-cycle success plan — 2026-10-27 + +The following draft snapshot is accepted unchanged before implementation. Its +SHA256 is `9616146b8b81c1adde23e906dcfa0b044b80ca0d3433fad25f7faac4f5ba2a57`. +Root PLAN R1 and independent Gemini PLAN R2 both returned GO at the same exact +base7b5/tree63977. Their receipt SHA256 values are respectively +`71a222c7603c97d9b21b519a2b029f6cfffe3ebcf4f17f2cbe9a39276ce1787b` and +`a2892a34e05a0e2cd841ea882ca625a5a23947ea296fdf4159ae1a901e2a0701`. + +Both actual historical raw reviews are now complete: root receipt SHA256 +`12c88c254bf41dc93ef4b6408e5539fd9ed4dabc496398d042561f8502d4b396` +and independent Gemini receipt SHA256 +`38f8d66cf2dc7bf743009b7535bea6d7ff02453fa6971637df9e31b9bbb55505`. +The snapshot below accurately says root review was pending when drafted; this +acceptance record supersedes that pending status only. The historical7b5 run +remains failed and wholly unqualified. Root's receipt explicitly attributes +reproduction of the reviewed peer parser and separately records root's direct +public/state/operation/receipt and native/provider/probe joins plus source review. + +Implementation watchpoints within the unchanged plan: a no-change batch update +may emit its own operation group while preserving state bytes and adding no +committed receipt; repeated add has no group. Actual archive write/close failure +must leave no independently admissible success archive. These are requirements +for source review and meaningful contracts, not exceptions to any guard. + +# Gemini complete-cycle final success: pre-code plan DRAFT + +## Decision and review boundary + +This is a source-only implementation proposal, not implementation authority or a +qualification result. Root and Gemini must independently approve the same final +plan SHA before any source change. Root alone commits and publishes. No native +client, acquired executable, public installer or scanner runs locally. No +production adapter, workflow, matrix selection, pin, budget or supervisor change +is proposed. VS Code and release work remain outside scope. + +Base: `/tmp/uap-gemini-missing-start-mark-current`, commit +`7b5b5a6e9da38ab8e5e528750e458424577b516c`, tree +`63977fa1944442e34e2e5773ab3053d3a3de3118`. + +The useful change is a final success path after independently recomputing the +complete retained raw evidence and recording actual ordinary final closure. +Deleting the intentional fatal barrier or changing flags on count completeness +alone is insufficient. The existing failed-only capture remains a separate, +unchanged admission route. + +## Actual starting evidence + +Run `40596063564`, native job `122518184021`, reached the intentional final raw +review barrier in `agentplugins_gemini_cycle_lifecycle_test.go:67` after 91,080 ms. +The summary records `cycle_observed_complete=true`, +`attempt_stage=complete-cycle-capture-review`, `runtime_attempt_complete=false`, +`test_failed=true`, all five qualification flags false, and authentication/model +qualification false. These facts remain historical failure evidence. + +The ordinary downloaded files are under +`/tmp/uap-gemini-7b5-root-40596063564`. The download manifest records: + +| Artifact | ID | API/outer SHA256 | Inner SHA256 | Members | +| --- | --- | --- | --- | --- | +| Native | 12776569713 | e27790cd5fd52275c549992586ccb0f2cb6f60ed3cf01d84221a88d3793099e5 | c9c0e358c17ba9af1e5e6f41892a7a51489ca038c7d5951fdc0da144a73e43e1 | 57 | +| Frontend | 12776914254 | 07cd9ee65d4f7fde403739cc95f486ae2f973a5df1e8d332bcf8fdfbd961b634 | fa42523a487267e152bb2c3b3b0a86bc45d92f900cff09253601c1775c5dd0bc | 25 | + +Gemini's independent raw audit is +`/tmp/uap-gemini-7b5-independent-40596063564/independent-raw-audit.json`, SHA256 +`38f8d66cf2dc7bf743009b7535bea6d7ff02453fa6971637df9e31b9bbb55505`. +It reports 24 frontend and 168 embedded stream joins; 16 public operations, +18 proof rows, 14 catalogs, 10 native sessions, 16 provider request/response +pairs; and 30 fresh probe PID/session groups with 30 initialize, 30 list and +6 call events. Root's own detailed raw audit is pending when this draft is +written. The draft does not treat the peer's receipt as two completed audits. + +Pinned source remains Gemini CLI 0.65.0, source +`6006c14a4decfe4b891c6263ad6ad5992e404b5b`, Node 24.21.0, the entire original +immutable member closure, current GenAI/protocol source blobs and scanner +identities. No new provider/native shape is admitted by this amendment. + +## Existing authority and reusable helpers + +The live cycle already performs the public lifecycle, restart, update, repair, +scope isolation, native startup/call/result and filesystem checks. Preserve the +sequence and existing helper bodies except the explicitly identified final +closure instrumentation and artifact finalization. + +| Existing source | Reuse in final admission | +| --- | --- | +| `agentplugins_gemini_cycle_fixture_test.go` | Exact fixed matrices, layout/recipes, byte receipts, private-data limits, original `check`, seeded foreign/settings authority. | +| `agentplugins_gemini_cycle_request_test.go` and `agentplugins_gemini_project_native_provider_test.go` | Strict declaration/schema, generation/safety/tool configuration, contents union, thought signature, request prefix, source-defined wire/native call projection and exact untrusted wrapper. | +| `agentplugins_gemini_cycle_stream_test.go` | Exact native JSONL init/prompt/tool-use/result/assistant sentinel/terminal grammar and timestamps. | +| `agentplugins_gemini_cycle_events_test.go` | Exact raw facts, advertised components, per-observation event grammar, global PID/session freshness, marker delta. | +| `agentplugins_gemini_cycle_skills_test.go` | Whole pinned/foreign/owned skill inventory with exact description, path, enabled/builtin state. | +| `agentplugins_gemini_cycle_proof_test.go`, `native_proof`, `source`, `public` | Strict current typed state, derived source/binding/data/object identity, committed receipt chains, selected public outputs and raw recipes. Reuse pure functions; live filesystem readers stay live. | +| `agentplugins_gemini_cycle_tree/file/closure/absence/assessment*_test.go` | All original live held authority, controlled absence, unchanged data/foreign/settings, assessment closure and snapshot guards remain unchanged. | +| `project_native_gemini_cycle_bytes.py` | Strict raw JSON, closed stream and row framing, whole-byte hash/base64 joins and nested privacy/resource refusal. | +| `project_native_gemini_cycle.py` | Reuse fixed constants and pure layout/command/receipt/stage helpers where suitable. Preserve its failed-only `members/_members` behavior and file bytes. | +| `project_native_gemini_cycle_proof.py` | Reuse independent source/state proof primitives as a baseline, plus stricter success-only chronology/receipt/public joins. Preserve the original module bytes. | + +The existing failed-only Python reader is intentionally not a success verifier: +it accepts structural failed prefixes and does not parse every native/provider +stream or catalog semantically. It cannot become a qualification authority by +substituting flags. Build separate strict success admission around retained +bytes, with symmetric Go/Python rejection predicates. + +## Finite matrices and chronology + +Keep every current public/listing/native stage in its exact order, with no new +native or public command and no omitted stage: + +* Public (16): git-a, git-b, git-user, version, add-user, add-a, add-b, + repeat-add-a, unchanged-update-a, intact-repair-a, update-a, missing-repair-a, + remove-a, repeat-remove-a, remove-b, remove-user. +* Catalog (14): baseline-a, baseline-b, baseline-user, installed-user, + installed-a, installed-b, repeat-add-a, unchanged-update-a, intact-repair-a, + updated-a, repaired-a, removed-a, removed-b, removed-user. +* Native (10): baseline-a, installed-user, installed-a, installed-b, restarted-a, + updated-a, repaired-a, removed-a, removed-b, removed-user. + +There are exactly 24 interleaved listing/native command rows, 24 probe segments, +18 proof rows, 10 provider receipts, and 16 request/16 response rows. The proof +timeline is the existing four source recipes, twelve public post-state proofs +and pre-revision/pre-fault proofs; full arrays and interleaving come from the +existing independent Go/Python fixed constants, not from summary-supplied order. + +Reconstruct stage-specific state snapshots while walking this fixed timeline. +Do not use the final A-two recipe for earlier installed/restarted A-one facts. +User is U-one throughout, B is B-one throughout; A changes only at the existing +source-a-A-two row, retaining its nonce, source path, probe identity and stable +installation/client/physical/data IDs. Each same-name scope has independent IDs +and paths. Removed bindings cannot be reused as installed components. + +| Native stages | Advertised tools | Selected operation | +| --- | --- | --- | +| baseline-a, removed-user | None | none | +| installed-user | U | write U | +| installed-a, installed-b | U plus selected A or B | write selected project | +| restarted-a | U plus A-one | read A retained marker in fresh process | +| updated-a, repaired-a | U plus A-two | read same A retained marker | +| removed-a, removed-b | U only | none | + +Listing stages use the corresponding point in the same timeline. Foreign rows +remain disabled, selected owned rows enabled, and both exact pinned builtin +skills remain present. Native no-call stages still require complete successful +fresh native sessions and exact advertised initialize/list activity; no empty +native stream or sentinel-only summary can stand in for this evidence. + +## Small final closure receipt and live success order + +Add one bounded closed `cycle_completion` object to the existing summary. Do not +add a ZIP member, raw profile inventory or new aggregate. Keep exactly 57 members +on success and the existing failed-prefix member closure. Cap the serialized +completion object at 8 KiB, within the unchanged summary/member/total limits. + +The receipt has exact fields: + +* `schema_version`: integer 1. +* `started_at`: the original `f.started` timestamp. +* `work_deadline_at`: exactly started_at plus 150 seconds. +* `finished_at`: observed after provider closure, final held checks and pure + semantic verification, before final summary serialization. +* `work_context_error`: boolean false on success, from the original context. +* `original_checks_error`: boolean false only after the existing final `c.check` + returned successfully; never default a skipped check to success. +* `open_authorities`: integer zero, from the held open-authority map. +* `open_events`: boolean false, from the existing append-only event authority. +* `provider`: a closed object containing `shutdown_complete=true`, + `forced_close=false`, `serve_returned=true`, `error=false`, `busy=0`, + `current_stage` equal to the empty string, `requests=16`, and + `completed_stages` exactly the ten fixed native stages. + +These fields are actual results of the existing owner close/check path. Extend +the existing provider `close` narrowly to retain the Shutdown result, whether +fallback Close was required, Serve completion and the final locked owner state. +Preserve its original remaining-to-started+180 deadline, handler waiting, +failure checks, pending-phase capture and completion ownership. Do not create a +new cleanup origin, replace real closure with a synthetic receipt or make the +record independently writable through a generic success/flag setter. An expired +origin or forced close produces failure evidence and cannot satisfy success. + +Live order is mandatory: + +1. Run the unchanged full matrix and existing checks. At the old deliberate + barrier, stage completion is only a provisional candidate. Replace the + intentional fatal with transfer to the already-deferred finalizer; there is + still no successful summary or qualification at this point. +2. Clear any staged completion/qualification before finalization. Ordinarily + close the original provider, await Serve return, collect actual receipt data, + and perform the existing original held-file/tree/absence/event/privacy checks. + Require original context healthy and original total bound intact. Require + no open operation or event segment, all exact matrices and no failed test. +3. Run the new pure Go complete-evidence verifier over the actual captured files, + held source identity and this real final receipt. It returns an error or a + private typed verified result. It must not take caller-selected flag names, + a generic `qualify` boolean or predeclared summary booleans as its authority. +4. Only this fixed complete verifier result permits the exact success mode and + all five cycle flags. Before serialization, check failure/context/time/privacy + again and validate the final summary+files. Any late error clears staged + proof/completion and every qualification flag, and retains a failed capture. + Archive creation/write/close failures fail the test and must not leave an + independently admissible successful archive; no valid complete ZIP plus + passing frontend can be claimed from an incomplete write. + +The final successful tuple is `capture_mode=gemini-complete-cycle`, +`cycle_capture_review_required=false`, `attempt_stage=complete-cycle`, +`cycle_observed_complete=true`, `runtime_attempt_complete=true`, +`test_failed=false`, exactly the five existing lifecycle/MCP flags true. +Activation remains Prepared at the top level, and project binding receipts +remain Prepared/Installed; the user binding retains its existing Active status. +Vendor authentication and real-model flags remain false. + +Every unsuccessful live attempt keeps the existing first-capture mode, review +required true, false runtime/all five flags and truthful failed stage/prefix. +It may retain a bounded failing closure object for diagnosis, but that object +never grants success. The historical 7b5 capture has no such object and remains +accepted unchanged by the old failed reader. In particular, its observed=true +does not substitute for the new receipt or semantic success mode. + +## Pure semantic success admission in both languages + +Both readers independently verify exact current source identity, pins, closed +layout, summary types, original budgets, final closure and all retained streams. +Neither trusts a proof hash, matrix length or qualification flag alone. Preserve +the exact JSON depth/key/node/UTF8/nonfinite/duplicate-key/privacy bounds; every +new nested object is closed with explicit allowed optional fields and exact +type/enum bounds. Python booleans must not satisfy integer comparisons. + +### Raw and public command closure + +Require precisely runtime-attempt.json, all 16 public triples and all eight +fixed aggregates, with no orphan, duplicate, path-like or unrecorded member. +Verify strict ordinary archive/member bounds, byte lengths, digests, base64 and +stream equality for every duplicated observation. Exactly one command row owns +each fixed observation. Scope/cwd/argv must match held layout and phase prompt. +Require clean ordinary supervisor receipts, exact exit/status semantics and +finite per-command bounds; native timestamps and duration must agree with each +other and fit the original interval. Public rows have no absolute timestamps, +so their relation to the original origin remains attested by the unchanged live +original context and final receipt; do not invent missing observations. + +Git output is empty and version is exactly 0.65.0. Public operations use current +strict actual public JSON, one selected Gemini target and matching selected +scope/installation. Parse the full source-defined nested result rather than +recursively searching for an arbitrary `mutated` key. Join source/tree/manifest, +physical/client/data IDs, package/native inventory and operation IDs to the +corresponding independent state proof. Mutating operations must join their new +committed operation-group/receipt to the public operation ID. No-change add and +update keep exact prior state bytes/receipt chains, and intact/missing repair +have precisely the existing committed-receipt deltas. Validate applicable +current security/subject/policy output against the held recipe and existing +source-defined assessment, without inventing an assessment for removal. + +Repeated remove is the exact natural exit 1/error=false/context_error=false, +empty stdout and whole fixed stderr refusal. It preserves the preceding retained +installation/data/removal receipt bytes and creates no extra committed receipt. +All other public exits are clean zero with exact existing progress stderr. + +### Source/state/receipt chronology + +Independently decode all 18 proof rows, four closed source recipes and current +schema-5 state. Reuse `geminiCycleState`, `geminiCycleSource`, +`geminiCycleBindingIdentity`, `geminiCycleReceipts` and derived domain identity +functions in Go where pure; build a read-only typed removed-state check around +their existing predicates. Python reuses the existing proof module plus new +success-only invariants. Neither reader calls live filesystem proof methods. + +Require one exact installation, no environment or unknown authority, independent +U/A/B identities, correct origin/package/source, stable source/data/client IDs, +all exact native objects/digests/paths and receipt-prefix preservation. Enforce +the exact stage-specific swap counts (U and B one; A one on add, unchanged for +repeat add/update, two after intact repair, three after update, four after missing +repair) and one matching removal receipt after the last swap. Check source +revision A-one to A-two only at its fixed row, correct no-change byte equality, +retained data receipt equality and removed clients empty/DataRetained true. +Do not derive the independent authored recipe from installed metadata. + +The three text source files are retained and rehashed; bin/probe is represented +only by length/hash/executable metadata. Preserve its exact cross-recipe/revision +identity and applicable frontend build identity, but do not claim the raw +artifact reader recomputed the complete packaged source digest from absent +executable bytes. The live source authoring/digest/payload checks remain the +authority for that relation; the reader enforces all available equality joins. + +### Catalogs and advertised component isolation + +Reconstruct all 14 exact expected catalogs with existing `geminiCycleSkills` +and a pure expected-row builder. Recheck pinned builtin file identities from the +retained immutable acquisition closure, correct descriptions and exact paths; +foreign selected-scope/user rows disabled; only currently installed scope/user +skills enabled with the right revision. Refuse unknown, duplicate, missing, +foreign-enabled, removed-present, wrong-path or malformed rows and unknown +controls. Use the preserved exact listing stderr grammar with the stage's +advertised components. Do not expand the SGR/parser or diagnostic acceptance. + +### Provider request/response and native joins + +For all ten phases derive expected scope, operation, tool set, nonce, prompt, +sentinel, native ID and wire ID from timeline state. Call phases have exactly two +request/response pairs; four no-call phases have exactly one pair. This yields +16 pairs; counts are consequences of these phase predicates. + +Use the unchanged strict Go request/schema/content/history helpers over every +raw request, setting only the replay phase's request count needed by the +existing parser. Reconstruct its initial contents/envelope from request 0, then +require the exact unchanged prefix plus one model call and one user response. +Validate all nested roles/contents/parts/function/declaration/optional config +objects with their original schema, enum and numeric bounds. The first request +has no prior call/result. Its final selected user text part equals the held +phase prompt; source-defined session-context text may precede it as separately +bounded text, without treating arbitrary foreign function history as context. +The native argv and native user event must carry the same held prompt. + +Verify each retained SSE response as the exact whole fixed framing (`data: `, +one strict JSON document, then two newlines), exact closed one-candidate model +response, STOP, index 0 and existing fixed usage metadata. First call response +contains only the selected functionCall with the exact native-prefixed ID/name +and held arguments; final/no-call response contains only the exact held sentinel. +The next request's converter-projected functionCall/functionResponse must carry +the exact wire ID, same name/arguments, source-defined thought signature and +one exact untrusted-context wrapper. No search, arbitrary stripping, extra +part/response/SSE event, foreign call or alternate provider route is admitted. + +Join the decoded facts object from that response to native tool_result and the +matching tools/call probe event, with exact nonce/revision/cwd/argv/root/data, +literal-once expansion and marker. Reuse `geminiCycleFacts` and +`geminiCycleStream`; require ten unique native sessions, complete stage-specific +event order, successful final result and exact assembled sentinel. Native +timestamps are ordered within the corresponding clean command interval; +optional stats use the existing closed pinned validator. Whole existing allowed +native stderr tuples remain unchanged; any other diagnostic fails success. + +### Probe, restart, marker/data and removal evidence + +Replay all 24 actual per-observation probe segments through the unchanged +`geminiCycleProbeSegment` with independently reconstructed advertised scope +recipes and phase facts. Use shared accumulated prior PID/session sets across +all listing and native stages, including both scopes. Only the exact advertised +components may initialize/list, and only the phase-selected component may call. +Require per-component initialize/list[/call] order, matching facts, clean fresh +PID/session/time bounds, no unknown/removed/unselected nonce or extra event. +Preserve listing's existing optional startup semantics; a native advertised +component always requires its complete actual initialize/list exchange. + +Write calls create the exact retained marker for U/A/B; restart/update/repair A +read the same marker and stable data locator through fresh native processes and +probe PID/sessions. A updated/repaired facts must report A-two, not stale A-one. +Retained data receipts remain identical through all later state/removal proofs. +Removed A/B retain only user declarations and can never initialize or call the +removed project; final removed-user has no tool or probe process. Final state +proofs show removed clients and retained owned data. Existing live marker +delta/data-owner checks prove no unrelated data changed; raw replay checks all +retained marker/facts/receipt identities without claiming absent full tree maps. + +### Independent Python route + +Add a separate success module (split into small protocol/proof modules only when +needed for readability/lint) and a narrow exact mode dispatch in +`project_native_runtime.py:attempt_members`. Existing first-capture MODE always +continues to the byte-identical failed-only module. The new complete mode always +requires the new strict success verifier and final receipt. Unknown modes, +mixed success/failure tuples and partial success are rejected; a new-mode failed +summary must not be normalized into a success. New live failures use old mode. + +Port the actual Go predicate rather than a simplified Python approximation. +Specifically parse public stdout, every selected catalog, all nested provider +messages/calls/config, SSE responses, native JSONL/stats, probe segments, source +state/receipt identity and final cleanup. Both readers must reject the same +coherently digest-updated semantic mutations. Preserve old 7b5, 239 and older +source-bound failed artifacts without retargeting source IDs or rewriting bytes. + +## Filesystem scope and limits stated honestly + +The unchanged live walker uses no-follow descriptor-relative open/stat checks, +held parent/link revalidation, exact descendant owner/group, regular-file +single-link checks, stable before/after records, sorted complete bounded +membership and checked close. Its actual limits are 64 levels, 4,096 nodes, +64 MiB per ordinary file, 256 MiB aggregate and the original context. Preserve +these exact limits and all CWD/state/profile/assessment/foreign/absence closures. +Do not add broad permission exceptions, baseline adoption or cache exemptions. + +Full before/after tree maps, physical owner-marker bodies and some live payload +bytes are not exported in the 57-member artifact. Independent readers cannot +reinspect the former runner filesystem or prove those missing observations. +They replay all retained raw bytes and state/facts/identity joins and require +the finite source-attested original-check/ordinary-close receipt. The unchanged +live source and genuine hosted process remain the authority for filesystem +closure and full supervisor containment. This is not a signed remote attestation. + +The walker compares device/inode to retain held identities; it does not use a +mount-ID policy or independently exclude all bind mounts, and this plan does not +claim that guarantee. Do not strengthen prose beyond source or silently weaken +filesystem guards in order to fit a success claim. + +## Expected implementation scope + +Existing edits are limited to cycle lifecycle (replace the intentional barrier +with provisional candidate handoff), artifact finalization (late-failure reset, +fixed success dispatch and strict pre-write admission), provider close (retain +finite actual closure results), and runtime Python exact mode dispatch. Add +small dedicated Go complete-evidence/proof/protocol helpers and their synthetic +contracts; add independent Python success helper(s)/tests and a concise +validation record. Keep unrelated source and all preserved helper bodies exact. + +Preserve byte-for-byte the failed-only Python cycle/bytes/proof modules and +their old contract fixture; retain original measured 2ff testdata and old +single-attempt code/readers unchanged. Existing production source, acquisition, +workflow/CASES selection, setup commands, process runner, fixture guard, source +recipes, native/listing execution, tree/filesystem closures and accepted stderr +helper are unchanged. If an implementation needs another scope, freeze and +return the concrete reason for independent plan amendment before proceeding. + +## Meaningful verification and review gates + +Create independent synthetic protocol records under clearly inert never-executed +paths with synthetic IDs/timestamps, not modified captured logs. Build at least +one coherent full 57-member successful fixture containing real strict catalogs, +provider request/response/native/probe joins and public/state receipts; it must +pass both independent readers. Reuse existing real staging/kernel/proof contract +fixtures when they exercise actual current state/identity semantics without a +public installer process. Synthetic acceptance never establishes native proof. + +Negative controls mutate actual semantic boundaries while updating surrounding +stream lengths/digests to avoid stopping at a superficial hash error: + +* Missing/extra/reordered/duplicate stage/member/JSON key; partial full-length + placeholders; foreign source/layout/pin; type/enum/overflow/nonfinite/deep or + oversized JSON; base64/UTF8/private nested key/string/JSONL violations. +* Public unknown/wrong target/scope/mutation/installation, forged operation ID, + stale package/security subject, receipt count/prefix/phase/path mismatch; + no-change changed state; repeated-remove fake zero/JSON or changed retention. +* Each catalog missing/foreign-enabled/stale-revision/removed/wrong path/builtin. +* Every nested provider unknown/missing/wrong role/part/call/config field, + extra tool/response/candidate/SSE frame, wrong native-vs-wire ID, changed + initial request envelope/prefix/prompt, wrapper or thought signature. +* Facts mismatch at provider/native/probe seams; wrong nonce/revision/marker/ + root/data/argv/expansion; additional call; wrong scope; stale A-one after + update/repair; PID/session collision across components or earlier stages; + changed timestamp/order; native error/cancel/missing final sentinel/result. +* Missing/forced/error/unfinished provider shutdown, busy handler or current + phase, missing final check, open authority/event, failed/expired original + context, incorrect original deadline/interval and total overflow. Stage a + candidate, then inject a late final check/privacy/admission failure and prove + all staged flags/proof are cleared before a failed summary can be serialized. +* Copy synthetic success summary/proof over old failure-shaped raw records and + ensure strict success admission rejects; independently replay the actual 7b5 + barrier capture with no final receipt, and actual earlier failed prefixes. + +Do not add native captures, log fixtures or acquired executables to Git. Scratch +replay must bind original source identities and hashes, read original 7b5/239 +and earlier representative prefixes through original and candidate failed +readers, and prove original raw/result bytes and allfalse outcomes unchanged. +Separately, relabeling a copy of actual 7b5 into new success mode without genuine +new final closure must reject. No old run is upgraded by this amendment. + +Root serializes gates. Required actual gates are focused complete/inert Gemini +cycle plus project/native-runtime contracts; all affected Python runtime, +old-failed-cycle and new-success contracts; gofmt/diff; affected all-enabled +lint with `--new-from-rev=a412ba5e137fdcb7e004393229b323211ed746e1`; and unfiltered +whole-repository revive/funlen/gocyclo/gocognit/dupl/depguard. Record exact commands, +source/tree, exit statuses and log digests. Do not skip a new success predicate +or containment check to make a gate green. Capability limitations are reported +as limitations and handled through reviewed genuine hosted proof when required. + +Two independent full exact-source CODE critics must read the entire new Go and +Python success predicates, finalizer/closure and positive/adversarial fixtures, +including all incremental fixes. Root alone publishes after measured gates and +review GOs. A fresh current-source genuine hosted full-cycle pass, matching +source/pins, exact frontend/native artifact joins and two independent raw audits +of actual final cleanup plus full semantic evidence are required before any +five-flag qualification claim. PR status alone, a local synthetic pass or the +old intentional barrier result cannot satisfy that final gate. + +## Base preservation hashes + +| File | SHA256 at the exact base | +| --- | --- | +| cycle lifecycle | b56e38a5fe96fea2e5b98c21a0a91c61ed4f9d51a7d3759dc996ca9e7801beb4 | +| cycle artifact | 39133d88b0f01f8e1014b011071e74e26e3d5cdd3ccbdb095bbc1d1e136e2fb7 | +| cycle provider | 4a3c64a8d67a0634be681bbdc4d3e7cb1873a8df7cad561d1cb25f1e93d959ad | +| cycle stream (preserve) | cdc0d30452f7f9c3613ff28172e46a321042d0cce80dd59ea5fb802d95ff15d4 | +| cycle events (preserve) | e0b7e39de82444d0e1bbdefe384b538cda05310c9a05ea570e023b5808f08edb | +| cycle skills (preserve) | d603f599cf7cfbff3dd15aa69d8d36b6c5cf7d65a0a8d84aea88a4727bb89609 | +| cycle tree (preserve) | e30e6c40d26c81a9607faae0130b05e774d5d57d3e6f6adad59fa55d1af0f20a | +| cycle fixture (preserve) | 5e6c0d15d4cb5e0e9d7250c5ccef955ff897a9d073cbaa7b7373d19c7b5abac4 | +| cycle proof (preserve) | b9431714e0166b91b3ff9a1b13bf99ed98a26cc2c2d684acc6e5af361e18e46f | +| cycle public (preserve) | 0d05ebfcd8cca016296109fe1eeccb11cd96d74ba7793fb2a4f4d568e451beb9 | +| Python failed-only cycle (preserve) | 2932228d2d609e5d44780455a1b964e50a4e563e5062775e1210ae578c3bda05 | +| Python original proof (preserve) | acf1da3ebcdd147410e855e8e3b5e9c28a7867d1281cffeb851c99d7379baa7f | +| Python byte/privacy (preserve) | 29d541fe94f05fba659c652ab00c642f75db6fe6405fe18436f9f6ab8228d068 | +| Python failed-cycle contracts (preserve) | 3d6990e6d16dabab1b4dcc7edb35bd82c13374faf895dfa6d179e4634cc16fed | + +This draft author performed source/raw reads and metadata inspection only. +No implementation, native/vendor execution, gates or Git/GitHub mutation was +performed for this proposal. diff --git a/docs/GEMINI_PROJECT_NATIVE_COMPLETE_CYCLE_FIRST_CAPTURE_VALIDATION.md b/docs/GEMINI_PROJECT_NATIVE_COMPLETE_CYCLE_FIRST_CAPTURE_VALIDATION.md new file mode 100644 index 000000000..60c5dd297 --- /dev/null +++ b/docs/GEMINI_PROJECT_NATIVE_COMPLETE_CYCLE_FIRST_CAPTURE_VALIDATION.md @@ -0,0 +1,112 @@ +# Gemini complete-cycle first capture: reviewed local implementation + +## Exact source and review boundary + +This implementation is based on published PR526 head +`2ff752a5909c96333786cfe80454fd8bf7be3a3b`, tree +`9a98d09f6ec25d3d22b137309035bf213f284839`. The equivalent local base is +`6bfce250a15d5a030c1d12cf37c2da5161f85998` with that exact same tree. +Root must preserve the published history when porting this reviewed slice. + +Plan-only commits are `2dad2735`, `496386c5`, `83d4ec23`, and `7c9a9329`. +Final plan SHA256 is +`82040ff9c4ee0eb9c7c41d2c9528e35a760ee65e7ff45029edfb7ea32ca773d1`. +Two independent reviewers approved the complete plan, exact arithmetic +correction, pinned builtin-catalog refinement, and local inert capability +control before the corresponding implementation changes. + +The code commit is `cb7b7abb3060dd6813e61b3ec3b52932c90ecc28`, reviewed tree +`18d2b8923c2f9f6dfe2cd3db1821947dec4b0a10`. Both independent reviewers read +all initial source and the complete correction delta, verified all 39 final +source/testdata hashes and the tree, and gave unconditional CODE GO after +the actual gates below closed. The exact review manifest SHA256 is +`a33ca02d5e3d21cc7ca80b2edeed740dd4727ad91be4f8954f3d46868e052ab2`; +initial-tree-to-final correction patch SHA256 is +`76a52a57723f3bb39974ac229e2f19f3e6ab1f82eb30988df788dbf1e2e1a6e6`. +This validation record changes no reviewed source bytes. + +## What is captured, without a qualification upgrade + +The selected Gemini test now performs the finite 16 public operations, +14 skill inventories, and 10 fresh native sessions from the reviewed plan. +One held provider owns at most 16 requests. Evidence has at most 57 members, +with the original 150-second work and 180-second final bounds unchanged. + +The cycle proves independent user/A/B source recipes, current typed state, +stable scope identities, complete payload and native ownership, owned data, +original settings, foreign components, restart/read, update, exact owned +directory repair, removal and retained-data boundaries. Original user +settings/trust/policy use finite held file and parent identity frames; +unrelated caches do not receive an invented preservation exception. + +The first complete genuine capture deliberately fails at the final raw-review +gate. `runtime_attempt_complete` and every lifecycle/MCP qualification remain +false, as do account authentication and real-model qualifications. A separate +reviewed amendment and a fresh successful genuine cycle are required later. +This local implementation is not a completed hosted lifecycle result. + +## Findings resolved before freezing source + +- Owned skill removal now checks linked and held regular-file type, owner, + link count and size before reading, uses NONBLOCK/no-follow descriptors, + retains post-read identity checks, and refuses real FIFO/directory controls + without changing the entry or an aliased target. +- Probe events now reject consistent PID/session collisions both among + current advertised components and against prior stages. The actual event + seam is exercised with matching U/A facts, not a masked nonce mismatch. +- Known original files retain full records and held parent identities. + Selected settings are reopened only for their authorized public operation; + the exact independently proved frame becomes the next baseline. Actual + chmod and atomic same-bytes replacement controls refuse. +- Both semantic privacy scanners recognize the unchanged constructor's + `uap-fixture-` plus 48 hexadecimal key namespace, including JSON-escaped + direct/nested values, keys and JSONL. Whole-member work/node/depth bounds + are retained, and raw literal key replacement alone is not treated as proof. + +Seventeen actual lint findings were corrected mechanically, including checked +test restoration, wrapped-error matching, import grouping, equivalent role +switch/regexp, preallocation, Linux link-count typing and unused parameters. + +## Actual local verification + +| Gate | Result | +| --- | --- | +| Focused `^TestGeminiCycle\|^TestGeminiProjectNative` Go contracts | PASS, 0.578 seconds | +| Real Loader/Planner/Stager/Kernel/Gemini adapter/Store user/A/B into independent Python proof reader | PASS in focused suite | +| Actual retained 2ff requests, six native frames, three probe events and builtin catalog replay | PASS in focused suite | +| Runtime and new cycle Python contracts | 25 PASS, 3.615 seconds | +| Independent CLI reviewer new cycle Python contracts | 7 PASS, 3.686 seconds | +| Independent desktop reviewer new cycle Python contracts | 7 PASS, 3.379 seconds | +| All-enabled affected-line lint against plan `7c9a9329` | 0 issues | +| Unfiltered whole-repotests revive/funlen/gocyclo/gocognit/dupl/depguard report | 0 total issues | +| gofmt, staged whitespace, five Python AST files | Clean | + +The local fixed-shell natural-exit control initially observed the existing +typed ordinary-containment prerequisite refusal. Its exact capability-only +local skip is documented in the reviewed plan; unconditional pure refusal +controls remain. No native or containment qualification is inferred from it. +Genuine hosted native execution still fails on missing containment. + +No native client, public installer process, hosted-guard positive or vendor +model was executed locally. Inert contracts use actual file-only adapters, +owned fixture files and the fixed local shell control only. + +## Genuine baseline retained unchanged + +The source-bound [2ff runtime run](https://github.com/777genius/universal-agent-plugins/actions/runs/40493698035) +and [2ff research run](https://github.com/777genius/universal-agent-plugins/actions/runs/40493697693) +were successful on the published baseline. Their native/frontend/research +archives had 21/25/51 closed members; the independent audit verified exact +source/tree/clean records, API hashes and 74 stream joins. All five broader +qualification flags remained false. + +The old actual 21-member successful single-attempt archive was replayed +through current admission after adding the new mode: it still passes with +its original successful-attempt state and all five qualification flags false. +Old source, fixtures and admission remain separate. The copied raw 2ff +request/native/probe fixtures are hash-bound; the exact catalog's trailing +blank line is preserved through a base64 test fixture and decoded SHA check. + +Root alone may publish to existing PR526 after a fresh expected-head check. +No new PR, release, account authorization or VS Code change is part of this +slice. Fresh genuine full-cycle raw evidence is the next required boundary. diff --git a/docs/GEMINI_PROJECT_NATIVE_EXPLICIT_ENV_EXPECTATION_PLAN.md b/docs/GEMINI_PROJECT_NATIVE_EXPLICIT_ENV_EXPECTATION_PLAN.md new file mode 100644 index 000000000..1d6414e37 --- /dev/null +++ b/docs/GEMINI_PROJECT_NATIVE_EXPLICIT_ENV_EXPECTATION_PLAN.md @@ -0,0 +1,116 @@ +# Gemini: compare native probe facts against the pinned explicit-env expansion + +## Source-bound actual failure + +Published PR526 head9f81687411249640a11a54650888cec76c4820d5 has tree +77539fdb1b365db9b1a0c4dd570525b18c08123f, identical to local637e7e7f. +Preserve all earlier provider signature/wire-ID, research refresh and terminal +diagnostic corrections, raw evidence and strict source/receipt/cleanup gates. + +Genuine runtime40459797233/job122045178580 now passes the prior provider part +union/HTTP identity boundary and reaches returned probe fact validation. It +fails with provider_error="returned probe authority/nonce/revision/cwd/marker +differs", provider_returned=false, exactly two recorded routes. Native exit144, +error=false, stdout2586 bytes; stderr1951 bytes has SHA256 +7626d482fac60c559c01d9733c6a61b7ba59b8097060cb972730c648292f90bb. +This complete failed stderr remains refused; no terminal-prefix allowance can +turn this nonzero command into success. + +Closed native12715011738 outer SHA256 +fb0c40cfa2bec951500007cba314ebf7bbc502a6f40c45fcbbe2350cd0314b5c +has21 members; frontend12714812896 outer SHA256 +05066a3ce792664e816ad1bba98135183ffafa1240b50621c60d51399f2cb44d +has25. Canonical unique ordinary ZIP/CRC closure, exact committed source/tree, +empty clean-source streams and all24 frontend command stream byte/hash joins +were verified. All lifecycle/MCP/auth/model qualifications remain false. + +The exact second provider request's untrusted-context JSON and independent +tools/call probe event agree. Comparing against held provider arguments and +the captured receipt gives this complete result: + +| Fact | Actual comparison with original independent expectation | +| --- | --- | +| nonce, revision, cwd, plugin_root, plugin_data, marker | exact match | +| argv | exact match, including literal third argument ${UNKNOWN} | +| pid, session | positive PID and nonempty session; independent event agrees | +| literal | exact `literal ` followed by the original fixture HOME | +| once | exact held target locator followed by `/` | + +Only literal and once differ from the current validator's unexpanded env-value +expectation. No authority path, receipt, call identity, marker or argv mismatch +is being exempted. + +## Exact pinned native behavior + +At google-gemini/gemini-cli@6006c14a4decfe4b891c6263ad6ad5992e404b5b: + +| Source | Git blob | Full-file SHA256 | +| --- | --- | --- | +| packages/core/src/tools/mcp-client.ts | 3d2c7bebf61f1b20cb020dcebe352a786b652aba | 798702155ab6e454392140f0057cc88a1370deb0df6fe9fe45f4f2147c1ecf0d | +| packages/core/src/utils/envExpansion.ts | c17d91e1f75ebe3690d575ecffbf732630b74a57 | 87bc78e960ca70985c1d687ebc8aaab65a5a37b084f720352e2f8d501cf371a1 | +| packages/core/src/services/environmentSanitization.ts | c0aceef5806473c6d4a7894034d18d620f108e91 | a739daa890975fb8c1bccbca0ec47f10f9b305fb120991de41025f4b6fe27be9 | + +Complete source files were independently fetched and git-blob hashes recomputed; +copies are under /tmp/uap-shell-fresh-oct27/pinned-gemini. mcp-client.ts +2348–2381 sanitizes the process environment and applies expandEnvVars to each +explicit MCP env value, while passing argv unchanged. envExpansion uses +dotenv-expand and specifies that missing variables become empty. Sanitization +always allows HOME. The actual Go f.env explicitly supplies the original HOME +and contains no UNKNOWN key. Thus the pinned native second pass expands the +authored literal env value to `literal ` + held HOME, and the once env value +to held target locator + `/`. This is native behavior after public UAP +materialization; the installed source bytes remain independently frozen. + +## Finite correction after two independent plan GOs + +Scope: repotests/agentplugins_gemini_project_native_attempt_test.go and the +existing native contract file, plus this plan. Change only the two expected +native facts: compare Literal to exactly `literal ` + f.base.Home and Once +to exactly f.binding.TargetLocator + `/`. Derive expectations only from the +already held original HOME/receipt target; never expand, trim or normalize a +received value or consult arbitrary ambient variables. Never accept both the +old and new forms. Do not write a generic env expansion engine or change UAP +production interpolation, package source, installed settings or native env. + +Keep the complete strict fact envelope, nonce/revision/argv/root/data/cwd/marker, +PID/session, provider ID/schema/route and independent probe event ordering/ +identity checks unchanged. In particular argv's ${UNKNOWN} remains literal. +Preserve exact nonzero/error/capture/cleanup failure and raw-output admission. + +Add inert controls through the actual full validateFacts path, with real owned +event-file captures and independently authored held HOME/target/data/nonce. +The exact expanded native fact set with its matching initialize/list/call event +closure passes. Old unexpanded values, wrong or sibling HOME/target, malformed +literal spacing, re-expanded argv, foreign root/data/nonce/marker/revision, +wrong PID/session and mismatched probe events still fail. Replay the actual +retained request2/probe event bytes against their captured receipt/call/HOME +authority offline; no native/vendor process or hosted guard runs locally. + +Run focused affected Gemini native contracts plus the retained raw replay, +then actual affected all-enabled and whole-file size/architecture lint under +the exclusive Go/lint slot, gofmt/diff checks and two independent code reviews. +Keep any temporary raw replay fixture out of the committed tree. Root alone +publishes to existing PR526 with a fresh ref/lease; no release/new PR/VS work. +Require fresh genuine source-bound success through provider/native/probe and +cleanup, and the complete separate lifecycle proof before qualification. + +## Implemented validation + +Both independent plan and complete two-file code reviews approved the exact +held-HOME/target expectation correction. The reviewed attempt SHA256 is +35e24166a72d3aaae56d686d2db38a6bdc6c15c4c062f862e15040c584490aa6; +contract SHA256 is +f29810c3b43f29ddc053d9aea59daa80ca4047ddc970c9b013e6649bb61b5eac. + +Focused existing/new TestGeminiProjectNative contracts and the temporary +retained request2/three-event replay passed in 0.022s. The replay independently +held the five captured member hashes, original installed unexpanded literals, +receipt target and original HOME from git-A cwd. The temporary replay file was +removed before lint and is absent from the committed tree. Actual all-enabled +affected lint against plan52593ecc and the unfiltered whole-file +revive/funlen/gocyclo/gocognit/dupl/depguard gate each reported zero issues. +The latter gate was repeated solely to recover its completion after session +output loss and completed exit0 with zero issues. Gofmt and diff checks pass. +No vendor/native process or hosted eligibility guard ran locally. This changes +no recorded failed capture or qualification; fresh genuine native evidence is +still required. diff --git a/docs/GEMINI_PROJECT_NATIVE_FINAL_COMPLETION_VALIDATION.md b/docs/GEMINI_PROJECT_NATIVE_FINAL_COMPLETION_VALIDATION.md new file mode 100644 index 000000000..af5af5eda --- /dev/null +++ b/docs/GEMINI_PROJECT_NATIVE_FINAL_COMPLETION_VALIDATION.md @@ -0,0 +1,279 @@ +# Gemini complete-cycle final completion + +## Review and qualification boundary + +This source implements the exact pre-code plan SHA256 +`9616146b8b81c1adde23e906dcfa0b044b80ca0d3433fad25f7faac4f5ba2a57`, +committed before implementation as `0dd08a36d73bafa48117b159f2cd4fb9988a75b3` +(tree `0b9e9530927edf969b50c7fe15295ba0cfe8198d`). The plan is appended to the +existing complete-cycle plan. Root and an independent reviewer accepted it +before code. Exact source CODE review, final gates and a fresh genuine hosted +completion are pending. This record conveys no native qualification or release. + +The measured starting capture is source +`7b5b5a6e9da38ab8e5e528750e458424577b516c`, tree +`63977fa1944442e34e2e5773ab3053d3a3de3118`, run `40596063564`, native job +`122518184021`. Its 57-member native artifact `12776569713` has API/outer SHA256 +`e27790cd5fd52275c549992586ccb0f2cb6f60ed3cf01d84221a88d3793099e5`; the +25-member frontend artifact `12776914254` has API/outer SHA256 +`07cd9ee65d4f7fde403739cc95f486ae2f973a5df1e8d332bcf8fdfbd961b634`. + +That run completed the finite observations and intentionally failed at the +independent raw review barrier after 91,080 ms. Its runtime and all five flags +remain false. Root and peer independently audited its actual source, pins, +frontend/native stream joins and semantic evidence before this amendment. +Nothing in this implementation upgrades that historical failed artifact. + +## Complete evidence and final closure + +The live sequence remains 16 public operations, 14 catalog observations and +10 fresh native sessions. Success retains exactly 57 members: 16 public raw +triples, eight bounded aggregates and the runtime summary. No new native/public +command, profile capture, ZIP member, workflow, acquisition pin or timeout is +introduced. + +The finalizer still owns the existing ordinary provider Shutdown, Serve return, +original held settings/foreign/source/data/event checks and original 150-second +work/180-second final origins. Its small closed `cycle_completion` summary +object records actual original timestamps, context/check errors, remaining open +authority/event state and the provider's final closure state. Forced close, +unfinished Serve/handler/phase, incomplete fixed stages, an error, expired work +or any failed test prevents success. + +The original source identity is copied deeply at the initial lifecycle boundary, +after registering finalization, and passed independently to final admission. +It is never validated by comparing the summary to itself. Archive entry checks +the same original work/total origins again: a newly expired origin fails the Go +test and invalidates staged observed completion before failed serialization. + +After these live checks, a separate pure Go verifier recomputes all retained +semantic evidence. Only its fixed complete result permits the new tuple: +`capture_mode=gemini-complete-cycle`, review-required false, stage complete-cycle, +observed/runtime complete true and test-failed false. Exactly the five existing +lifecycle/MCP flags are true in that tuple. Top-level activation stays Prepared; +existing user/project receipt activation statuses are preserved. Authentication +and real-model qualification remain false. + +Every failure clears staged runtime and qualification fields. It retains the +old first-capture mode and failed-prefix semantics. The successful archive is +written to an exclusively owned partial file, with checked ZIP and file closes, +then atomically exposed at the final name using Linux `RENAME_NOREPLACE`. +Failed writes/closes cannot publish a successful final ZIP. There is no fallible +partial-file cleanup after a successful atomic expose. + +## Independent semantic readers + +The Go reader and a separate Python success route validate the complete retained +bytes and identity joins. The original failed-only Python cycle/byte/proof +modules and contracts remain unchanged. They continue admitting the original +7b5 and earlier failed prefixes with their original source identities and false +outcomes. Unknown modes and mixed success/failure tuples are refused. + +Success requires the exact matrices and chronology, current typed source/state +and public results, stable independent scope IDs and data receipts, unchanged +receipt prefixes, exact mutation/removal operation groups, source revision, +catalog contents, full provider requests and fixed SSE responses, native/wire +call identities, exact return wrapper and facts, fresh native/probe processes, +sentinels and terminal success. Counts and completion booleans alone do not +satisfy admission. Digest-updated semantic contradictions must also reject. + +The A-one installed/restarted evidence is interpreted against its original +stage recipe; only updated/repaired A uses A-two. Repeated add/update preserve +state bytes and committed receipts. Repeated removal remains the exact ordinary +exit-1 refusal with empty stdout and unchanged retained state. Removed project +components cannot initialize or call, and the final removed-user session has +no tool declaration or probe process. + +Optional native stats retain the existing closed schema and additionally join +the selected model and phase call count. Exact timestamps use ASCII RFC3339 dates, year 0001–9999, an optional period +with one through nine fractional digits and Z or a numeric offset with hour +00–23 and minute 00–59. This lexical boundary covers closure, state, command, +native and probe timestamps before the preserved permissive parsers run. +Durations preserve nanoseconds before flooring to milliseconds; readers must +not introduce a rounding allowance through truncation or normalize comma, +over-precision or invalid-offset aliases. + +Success-only scalar checks use canonical integer types, including the integer +generation and stats fields accepted by reused broader validators. Finite +temperature values remain supported. Metadata and command text is bounded and +NUL-free. Acquisition metadata permits at most 512 members and 1 GiB per declared +member, covering the fixed observed 491-member bundle without relaxing the live +acquisition/file guards; names exclude dot/dotdot and runtime aliases. These are +reader metadata caps, not a claim that the live filesystem allows 1 GiB files. +Distinct U/A/B source nonces are mandatory before nonce-keyed probe maps are +built, and A-two must retain A-one's nonce. All base64 is canonical. Unpaired +UTF16 JSON escapes are refused before the old decoder could replace them +lossily. This includes complete nested JSON strings, keys and JSONL under the +original shared four-times-text, 16,384-node and 64-depth privacy budgets; +incomplete ordinary text containing backslash-u remains ordinary text. Valid +pairs, raw UTF8 and literal U+FFFD remain supported. The old shared +decoder/privacy helpers remain unchanged. + +The unchanged live provider compares decoded JSON number token text across the +initial and second request envelope. The independent Python success reader +therefore performs a bounded secondary numeric-token comparison after its +primary strict load and schema checks. Identical finite floats remain valid; +changing only 0.5 to 5e-1 or 0.50 is refused without normalizing retained bytes. + +## Filesystem and provenance limits + +The existing live no-follow descriptor walker, owner/group/type/single-link +checks, held parent/link identity, complete membership and before/after records +remain unchanged. Bounds remain 64 levels, 4,096 nodes, 64 MiB per ordinary file, +256 MiB aggregate and the original context. Original settings, foreign files, +data, source revision, controlled absence and assessment cache closure keep their +existing live authority. No baseline adoption or new cache exception is added. + +The artifact does not contain full before/after filesystem maps, all payload +bytes or the compiled probe binary. Readers cannot reinspect the former runner +filesystem or recompute the full package digest from missing executable bytes. +They validate retained text files, inventory hashes, source/state/public/facts +and data-receipt joins, plus the finite source-attested live final receipt. +The complete acquisition/runtime member metadata is checked as a closed pinned +inventory, but actual distribution/probe bytes remain bound by the genuine +frontend acquisition/build and independent raw audit. The receipt is not a +signed remote attestation. The walker does not add a mount-ID policy or claim +that all bind mounts are excluded. + +## Development verification so far + +The early source-bound focused Go compile and initial completion seam/closure +contracts passed in 0.108 seconds. They include actual in-process +Loader/Planner/Stager/Kernel/Adapter state into the new pure reader, a finite +closure contradiction matrix and real inert loopback HTTP close. No native, +probe, scanner or public installer process is executed by those contracts. + +An independent full synthetic fixture combines that actual in-process staging +seed with manually authored public/catalog/provider/native/probe records and +synthetic timestamps. It is not a retained capture. Its first compiled run +found an omitted removed-stage catalog mapping in the fixture; that fixture +mapping was corrected and the failed log retained. + +The final authored Go development run executed +`go test -json -p=1 -count=1 -timeout=180s ./repotests -run '^(TestGeminiCycle|TestGeminiProjectNative|TestProjectNativeRuntime)'`: +61 top-level tests and 346 cases passed (package JSON elapsed 8.261 seconds). The only skip is the unchanged pre-existing local +ordinary-containment capability control. No new completion test is skipped. +Source hashes and raw JSON events are retained outside the repository; the log +SHA256 is `25d7f0aef94f5df6cd8e91ca709bb8d4dc598657d2771fdf6a688c7000607d9f`. + +This run covers independently authored full 57-member Go and Python fixtures +admitted by the other reader, digest-updated semantic contradictions, coherent +nonce alias with omitted User events, coherent unpaired-surrogate and NUL +sessions, complete nested JSON value/key/line scalar controls, exact timestamp +grammar and nanosecond timing, canonical base64 and strict numeric types. +Real owned-output tests cover actual write and close errors, pre-expose failure, +and existing final/partial paths without replacement. Three actual inert Go +children exercise prior test failure, newly expired work and expired total +origin at archive entry. Each child fails, clears every staged flag and exports +only a truthful failed 57-member archive admitted by the preserved failed reader. +These own Go/Python fixture processes do not invoke a native client, public +installer or scanner and do not impersonate a hosted environment. + +Python's independent author separately executed the new and preserved contracts, +source-bound historical 7b5/239 failed replays, Unicode, timestamp and coherent +scope-nonce alias controls. Its final numeric-token correction passed three +focused groups in 3.926 seconds, including independently reproduced full +57-member finite-float positives and envelope-token drift negatives. Its exact +five-file source refreeze is SHA256 +`259d3e7ca6cc763a1bec8e5d2b47ecb16aa2544a6fa1c412a69919b4f46b7a53`. +All four old failed-cycle Python module/contract files remain byte-identical. +These development checks precede the root's immutable code commit and formal +CODE reviews; the complete final gates and fresh native run remain pending. + +Before publication, root requires a frozen source manifest, two independent +full CODE reviews, focused Go/Python contracts, affected all-enabled lint, +unfiltered whole six-linter checks and unchanged-source raw failure replays. +After publication, a fresh genuine hosted pass and independent raw audit of +source/pins, all semantic joins, ordinary closure and preserved guards are +required before a five-flag completion claim. Synthetic success or a green +status alone is insufficient. + +## Final immutable CODE and local gates — 2026-10-28 + +Final code is `e57e7fd291a9ba7c6ee5d4852de9a0ba6c933d3f`, tree +`26325284be19c0ed633f2bdb755234c66eac34f0`. Root CODE R1 and independent +Kimi CODE R2 both approve this exact source. Their retained receipt SHA256s are +`d67f3e96d601086e3c594f95a98091bb43b52e3223871d757b541e89d1bb1252` and +`f7a7e6037a5f99ebdbd4cbb79b9f9b356116931ce88c3d717bcab568b49f02af`. +The source freeze is `b582aa2e36f7b58037c07274e506baaf332c6464d29e6dca43de71e8efe84ceb`; +the reviewed mechanical lint correction is +`44dc6799435618a7f9fbfae5c7c4b4636731f5ceaaeb16096d79a84effec4842`. + +The final focused Go selection passed 61 top-level tests and 346 cases, retaining +only the unchanged old local containment-capability skip. Both actual affected +all-enabled lint (from `a412ba5e137fdcb7e004393229b323211ed746e1`) and unfiltered +whole six-linter gates report zero issues. All 76 old/new Gemini and runtime +Python tests pass. The Python and original/current historical 7b5/239 raw replays +transfer from `81d94fb4ee763689682d80e0e20f5431e998ff63` through the identical whole +`scripts` tree `bbcef77782fd25a36fe6c916aff68a7f4e94c688`. Both full original reader +snapshots contain all 105 script files; no AST extraction was used. Original +57-member and 27-member results remain identical, failed and all-false; relabeling +them without genuine completion is refused. Initial failed lint results remain +retained. Final gate receipt SHA256 is +`1eb2d30dc74a8d47fb53c2e782ffcbf45d345d711437f16d3f95104a31ec4fe6`. + +This publication changes only this record after the tested code commit. The +fresh genuine hosted native run and two independent raw audits are pending. +No historical failed archive is promoted, no native authentication/real-model +qualification is claimed, and no release is authorized by this record. + +## Qualified leaf and preserved Kimi-parent composition + +The exact Gemini leaf `0d31b77c190b72c04a606dbc3f3ea28256a1d0c3`, tree +`3e914e0fdddd60676cda3e0f1d08b1868dab1ea6`, passed all jobs in genuine +current-source run40612308701, including inherited Cline. Two independent +whole original RAW audits verified57 native and25 frontend members, +24 frontend and168 embedded stream joins, source/build/pins,16 public commands, +14 catalog observations,18 proofs,10 fresh native sessions,30 fresh probe +PID/session groups,30 initialize/list pairs and6 owned calls. The full cycle +completed in91.910s with ordinary provider and held-authority closure. +All five Gemini qualification flags are true; vendor authentication and +real-model qualification remain false. Root RAW receipt SHA256: +`ef054ab5b35324d2a777a91c6948395f2f1da833a58051a1a7af3336714d24fd`. +Independent RAW receipt SHA256: +`9fb8e1c178facff2ceff32d50fdd96b85ca55bb1d113fe0caebd5f1e8dcccee5`. + +Normal merge `752016c98aaa3d338875d663283b925636b02ca1`, tree +`71955bf998cf4cada2d84ff812ebabf239e08208`, composes that leaf with qualified +parent `888ef9f5d0f19ef305374bf87b1dd4133e21d578`. All161 nonshared owner +blobs/modes and5907 complete tree entries match the independently constructed +proposal. Runtime merge preserves all39 function/class bodies and the complete +owner ASTs. The two documentation conflicts retain each complete owner block; +the two earlier Gemini API-key corrections also remain intact. Root and +independent Native exact composition CODE GOs have receipt SHA256 values +`9e25bb8ab56c070faeba21fca38cdab07bc74173d3ca938e5d31ac92f8eba53c` and +`14c2d077378394194ab86dd0e868c44c442e9d86f71e9a37ef44b6bd426058e8`. + +New combined-source root contracts passed98 top-level tests/508 case events, +with only the unchanged local containment-capability skip. The joint seven +Python suites passed146 tests in37.366s. Root and CLI affected all-enabled +and whole unfiltered six-linter checks all exited0 with zero issues. +The local CLI command remains recorded as exit1: three saved-Git cases meet +the unchanged ordinary_unsupported process boundary, with21 top-level and77 +case passes. This failure was not relabeled or bypassed. Actual unfiltered +remote CLI core coverage from run40605865956/job122545088401 transfers through +identical complete CLI/dependency/workspace/Makefile/workflow bytes. Its actual +PR merge checkout4528916 has the exact eb69 source tree; required CLI packages +passed123.440s/127.727s. The nonverbose log supplies package results, not +invented individual event counts. SDK evidence transfers only its original +recorded intact-repair and lint scopes through complete module/input identity. + +Eight historical/successful archives were replayed in sixteen complete +original/current reader processes. Full results and every raw byte remain +identical; no source identity is retargeted. Gemini and Cline0d31 each retain +five true flags. Kimi eb69 component retains lifecycle/restart/initialize/list +with call false; its single-call lane retains the three MCP flags with +lifecycle/restart false. Their union covers the five cases, while neither +individual Kimi archive is described as five-flag complete. All authentication +and real-model flags remain false. + +Combined gate/transfer receipt SHA256: +`523345f777b0ec4326b49f45625fd720bf52b61bfab6b850f7d5d6d6b2ab88cc`. +Whole-reader preservation receipt SHA256: +`168c14f9396777f2ccd01d12f657d03bd7941da89841a03b29d03003935c3031`. +Verified module gate transfer receipt SHA256: +`b95c60d8d3652ed9e37c5aa804efe418981fe7d8b3f9641153f9b5dfd29254cd`. +This publication appends only this validation record after the reviewed merge. +Fresh combined-source CI/native evidence and applicable merge gates remain +required. No leaf archive is relabeled as combined-source evidence, and no +release or VS Code expansion follows from this composition. diff --git a/docs/GEMINI_PROJECT_NATIVE_INSTALLER_TEMP_CLOSURE_PLAN.md b/docs/GEMINI_PROJECT_NATIVE_INSTALLER_TEMP_CLOSURE_PLAN.md new file mode 100644 index 000000000..65bb573ed --- /dev/null +++ b/docs/GEMINI_PROJECT_NATIVE_INSTALLER_TEMP_CLOSURE_PLAN.md @@ -0,0 +1,134 @@ +# Gemini: preserve the exact public installer temporary parent + +## Current genuine boundary + +Authoritative source is PR526 commit +`fa7b9db9a94e39392934be5b3820f6266900c13b`, tree +`0310327c0dc9ec64036b99bb99387bdecf750cbc`. Genuine runtime +40553310025/job122371029305 failed after 14.68 seconds at `add-user` with +`Gemini public mutation escaped exact state closure`. It did not reach the +deliberate final complete-cycle review barrier. + +Native artifact12759975048 has outer SHA256 +`192004ce23896d107f29416cb1e5ec98fad5f45b09d5bdaf27098321dab2d3b9`, +inner `37ac4cb99bd9cf54e4ad46d93595dc5ddb29a1b5b22fabb108fedf68f74d0ac6`, +and 24 closed ordinary members. Frontend12759440510 has outer SHA256 +`6a6debcfb4b9d52b74706f2e1a873e6e560e826d4118d44e55404ea19a6b0b98`, +inner `953419512eec6d520e0980beb971b576f0125089159cf3bd65f762b1f1676c61`, +and 25 members. API sizes/digests, canonical unique ordinary ZIP/CRC closure, +exact source/tree/clean identity, all24 frontend stream joins and current +failed-only admission passed independent review. Three baseline catalogs and +the actual empty baseline-a native session completed normally: one provider +request/response, no owned declaration, call or returned tool facts. The public +add-user command completed before its independent state closure refused. + +The source does not export the refused relative path or the selected tree +delta. Therefore this plan does not claim to identify an uncaptured path +value. It corrects an independently provable observer omission at that exact +boundary. All runtime-complete/observed-complete/qualification/account/model +flags remain false. The provider's incomplete full-stage closure is truthful +on this prefix and must not be reclassified as successful cleanup proof. + +## Source proof + +At this exact source, cli/cmd/agentplugins/compose.go configures the real +installer with `TempRoot = StateRoot/installer-tmp`. The installer's +`Engine.ensureDirs` creates that exact parent with mode0700 along with its +other owned state directories. Its file-only `LocalPackageTreeDigest` also +creates the configured temporary root and removes its temporary snapshot +on return, including an assessment refusal. + +The fixture's geminiCycleStateClosure recognizes the state root, +operations-v2, and independently selected managed/data ancestors. It omits +installer-tmp. A newly created empty installer-tmp therefore reaches the +fatal unknown-entry branch even though every preceding source/binding, +payload/data/config/native-object proof has passed. Current inert cycle +contracts invoke Loader/Planner/Stager/Kernel directly and do not create +the public facade's temporary root, explaining the coverage gap. + +## Minimal implementation after two plan approvals + +In the existing client-specific geminiCycleStateClosure, validate the exact +literal `installer-tmp` through the existing geminiCycleParent check BEFORE +the generic unchanged-entry fast path. If present, it must be an ordinary0700 +directory, and an existing entry must retain its device/inode/owner/group/mode +identity. Also refuse every `installer-tmp/` descendant BEFORE that fast path; +this prefix is a refusal only, never an allowance. Otherwise unchanged +preexisting children or an unchanged0755 parent would skip the old checks. +The held no-follow bounded tree walker continues enforcing owner, ordinary +type, identity and read/close checks. Do not add a mutable subtree exception. + +Every installer-tmp descendant remains an unknown entry and must fail. +The actual public facade creates this parent and must leave it empty. This +correction does not require inventing it in legacy in-process Stager-only +fixtures whose before/after maps both lack it. Deletion of a present parent, +replacement, wrong mode/type/owner, alias, child residue, and changes to any +other original state/data/caller entry remain failures. Subsequent native +operations still freeze the complete state tree, including this directory. +Keep all source, payload, native profile, data, state/receipt and sibling +preservation checks in their existing order before adopting a proven map. + +Scope: the existing client-specific closure Go file, one bounded inert +contract file, and an accepted plan/validation record. No production source, +shared helper, Python schema/admission, selector, provider, diagnostic, +scanner, permission, trust, process/host, acquisition/pin, budget or VS Code +change. Keep this distinct from the separately reviewed mechanical lint +proposal, even if root later publishes their reviewed commits together. + +## Meaningful inert verification + +Exercise the actual public installer Engine in process, never an installer +or vendor executable: configure its explicit Gemini registry, owned state +root and exact installer-tmp path, and call LocalPackageTreeDigest on an +ordinary independently authored source. Leave Assess absent and trusted-local +policy false. Require the real ErrAssessmentRejected outcome, not a mocked +allow, and prove that its snapshot cleanup leaves exactly the empty0700 +temporary parent, no state/lock mutation and unchanged source/caller bytes. +Compare real before/after tree captures through the actual closure helper. +This is an inert file-operation/refusal contract, not native or scanner proof. + +Add actual owned-file/directory controls for retained parent identity, +new child residue, an unchanged preexisting child, wrong mode including an +unchanged0755 parent, regular-file substitution, symlink and same-path +replacement. Preserve and exercise an unrelated caller-owned +mutation refusal. Both the tree reader and closure must fail where their +respective contracts apply; do not fabricate stat maps or run a positive +hosted guard. Existing user/A/B proof contracts remain required. + +After root R1 and an independent R2, implement in an isolated current-head +worktree and obtain independent exact-code review. In one coordinated Go/lint +slot run the focused existing/new Gemini cycle/native contracts, all-enabled +affected lint and unchanged unfiltered whole-file architecture/size lint; +check gofmt and whitespace. Do not repeat vendor execution locally. + +Root alone publishes a reviewed frozen amendment after a fresh expected-head +check. A fresh genuine cycle must establish what follows this source defect. +If another discrepancy remains, preserve its exact failed prefix and review +it separately. This correction never completes or qualifies the old capture. + +## Accepted implementation and validation (2026-10-27) + +Root R1 and independent native-CLI R2 approved the exact revised proposal +SHA256 `75516f3ef0935ad81026a61ef838bc2c590c9a8371e738196a83a75a4a1f540a` +before implementation. The exact parent check and every-descendant refusal +precede the unchanged-record shortcut. No CWD/profile/payload/data closure +rule changes. Both-absent legacy fixtures remain valid. + +The new actual Engine contract keeps Assess absent and trusted-local policy +false, obtains ErrAssessmentRejected, and checks real snapshot cleanup into +an empty0700 parent with unchanged source and caller inventories. Ordinary +real-file controls cover retained/both-absent parents, new and unchanged +children, new and unchanged0755 mode, file substitution (including unchanged), +symlink refusal by the tree reader, same-path replacement, deletion and caller +mutation. No synthetic stat maps or positive hosted guard is used. + +Focused `^TestGemini` inert contracts passed in1.090s. The unchanged +all-enabled root lint against base443fa8d and the unfiltered whole-root +revive/funlen/gocyclo/gocognit/dupl/depguard gate each report zero issues. +The original sandbox first refused existing loopback/process-containment +contracts; the authorized inert suite passed with those real local capabilities +available. An initial new caller-mutation control used an exclusive-create +writer for an existing fixture; it was corrected to a checked ordinary file +write before the passing run. No vendor or public installer executable was +run locally. The old genuine failed prefix and all false qualification flags +retain their original meaning. A new genuine hosted run remains required. diff --git a/docs/GEMINI_PROJECT_NATIVE_INTEGRATION_LINT_PLAN.md b/docs/GEMINI_PROJECT_NATIVE_INTEGRATION_LINT_PLAN.md new file mode 100644 index 000000000..d2ffcfcaf --- /dev/null +++ b/docs/GEMINI_PROJECT_NATIVE_INTEGRATION_LINT_PLAN.md @@ -0,0 +1,125 @@ +# Copilot and Gemini: nine integration lint corrections + +## Evidence and exact source boundary + +This is a review proposal, not an implementation or a qualification result. +Root's combined integration is commit +`d1b1f51c98ffd0142993456b51762f7331aed6b7`, tree +`7906245dd8cb1287ebd78dd13b300aec99091fe3`, based on current main +`bd205dda` and the active project program. Root's actual full-delta all-enabled +lint against main reports exactly nine findings in +`/tmp/uap-active-nine-integration-lint.log`. Integration Go contracts passed +in 5.273s and 216 Python contracts passed in 31.782s before this proposal. + +The authoritative leaves are Copilot PR527 +`9b8ddc5332d70ca0c8d39c41c5ce60f3bba1c6e7`, tree +`8386a313607a2d1acfd5583bd9335d9ce7af1340`, and Gemini PR526 +`fa7b9db9a94e39392934be5b3820f6266900c13b`, tree +`0310327c0dc9ec64036b99bb99387bdecf750cbc`. Their relevant source files are +byte-identical in the combined integration. Their new genuine native captures +are still pending; preserve those source identities and wait for their raw +evidence before applying or publishing a follow-up to either leaf. + +## Exact changes + +| Client and existing file | Actual finding | Proposed correction | +| --- | --- | --- | +| Copilot provider, message validator | gocritic argument-order heuristic at the role membership expression | Name the exact existing delimiter string as a local constant and keep the same `strings.Contains(collection, token)` call and refusal. | +| Copilot provider, message validator | staticcheck De Morgan expression | Replace the negated assistant-and-calls term with its exact equivalent `role != "assistant" || !hasCalls`, preserving the surrounding missing/null-content condition. | +| Copilot provider, `start` | noctx `net.Listen` | Change only this private method to `start(ctx context.Context)` and use `(&net.ListenConfig{}).Listen(ctx, "tcp4", "127.0.0.1:0")`. | +| Copilot contract, existing JSON controls | gofmt at the hostile JSON table | Apply ordinary gofmt; retain all cases, order, bytes and assertions. | +| Copilot contract, hard-link refusal diagnostic | misspell `hardlinked` | Use the plain diagnostic `immutable file with multiple links accepted`; keep the actual link/refusal test unchanged. | +| Copilot contract, provider request authoring | noctx `httptest.NewRequest` | Use Go 1.22-compatible `http.NewRequestWithContext(context.Background(), ...)`, check its error with `t.Fatal`, and retain the exact request target as `RequestURI`. | +| Gemini contract, native stream role branch | staticcheck tagged switch | Convert only the existing user/assistant/default if-chain to `switch row["role"]`, with identical stage checks, assignments, returns and default refusal. | +| Gemini contract, provider request authoring | noctx `httptest.NewRequest` | Use the same Go 1.22-compatible context-aware request construction, checked error and exact `RequestURI` preservation. | +| Gemini provider, `start` | noctx `net.Listen` | Apply the same private context parameter and `ListenConfig.Listen` change as Copilot. | + +Each provider has exactly one actual `start` caller, in its existing +`agentplugins__project_native_attempt_test.go`. Pass that fixture's +already-held `f.ctx` from the caller. This adds the two caller files to the +four finding files; do not add a provider context field, alter constructors, +or add a fresh deadline. Gemini's complete-cycle provider already uses its +held context and is not part of this change. + +The authoritative leaves still declare Go 1.22 even though current main uses +a later Go version. Do not use `httptest.NewRequestWithContext`, a newer API. +The replacement retains method, absolute URL/route/query, body, header and +host mutations, response-recorder path and direct handler invocation. Retain +`RequestURI` as the original absolute target to preserve the incoming-test +request shape. No request is sent to a real service by these controls. + +The role warning is a false-positive argument-order heuristic, not evidence +that the arguments should be reversed. Naming the existing collection makes +the intent explicit without changing the accepted input set. The primary +go-critic rule in `checkers/rules/rules.go`, Git blob +`f7bdf35aed2f539428de7359d477f43de856ab68`, expressly exempts a named first +argument. Preserve the original membership behavior; do not fold a distinct +role grammar change into this lint correction. + +## Preserved authority and behavior + +Keep listener address/family, provider routes, body bounds, exact credentials, +HTTP timeouts, ordinary server close, request/response counts and one-call +ordering unchanged. Using the fixture's existing context only binds listener +creation to its original work budget; it does not replace provider shutdown +or process/cgroup supervision. + +Keep all source and executable pins, independently authored installed files, +the held firstLaunchAt/original-config digest, Gemini trust/settings/policy, +native argv/environment, package/data/receipt authority, permission and +approval checks, privacy/redaction and artifact admission unchanged. The +original work/total deadlines and fatal cleanup checks remain mandatory. + +Copilot remains its deliberately failed native-grammar review capture, with +all five qualification/authentication/real-model flags false. Gemini remains +its deliberately failed complete-cycle first capture, with the same false +flags and separate future completion requirement. Do not promote historical +or newly pending artifacts as a consequence of these lint corrections. + +Scope is the two existing provider files, two existing contract files, two +existing legacy-attempt caller files, and a truthful plan/validation record +per authoritative leaf. No shared Python/Go helpers, workflows, selectors, +production adapters or VS Code-specific files change. + +## Review, validation and publication + +Obtain root R1 and independent Kimi-owner R2 against this exact proposal +before implementation. Review actual new native artifacts first and reconcile +the exact current leaf heads. Preserve any separately required raw-evidence +fix as its own reviewed change; do not silently expand this plan. + +After the two plan approvals, apply the small changes in isolated worktrees +from the authoritative current leaves. Obtain independent exact-code review. +Use one coordinated exclusive Go/lint slot for the existing focused Copilot +and Gemini contracts, gofmt/diff checks, all-enabled affected lint and the +unchanged unfiltered whole-file architecture/size lint. Root should also +rerun the actual integration full-delta lint against main to close all nine +reported findings. Do not add mechanical mirror tests or rerun vendor clients +locally. A lint or compiler failure remains a failure to resolve, not a reason +to add suppressions or change toolchain declarations. + +Root alone publishes each frozen reviewed leaf after a fresh non-forced +expected-head check, then reintegrates it. Preserve the current pending run's +source/evidence identity. Native observations from an older head are not +retroactively relabeled as results of these later source changes. + +## Accepted implementation record (2026-10-27) + +Root R1 and independent Kimi-owner R2 approved the exact proposal SHA256 +`33cf3a7e9400e451b0ced924c71029fdaf2c21efb2110618489bf3aaafddd6a4` +before edits. The genuine source-bound runtime 40553310025 has now completed and +its current native/frontend artifacts were independently reviewed before this +follow-up. Historical observations retain their original source identities. + +This commit applies only the three existing Gemini Go files named in +the proposal. Evidence-driven changes are separate commits with their own +accepted plans. Validation results are recorded after the required gates. + +### Validation + +After the approved mechanical edits and the separate temporary-parent fixture +correction, all focused `^TestGemini` inert contracts passed (1.090s). +The unchanged all-enabled root lint against base443fa8d and the unfiltered +whole-root revive/funlen/gocyclo/gocognit/dupl/depguard gate each report +zero issues. No vendor or public installer executable was run locally. +The complete-cycle runtime still requires a fresh genuine capture. diff --git a/docs/GEMINI_PROJECT_NATIVE_PROVIDER_PART_PLAN.md b/docs/GEMINI_PROJECT_NATIVE_PROVIDER_PART_PLAN.md new file mode 100644 index 000000000..78d7c557d --- /dev/null +++ b/docs/GEMINI_PROJECT_NATIVE_PROVIDER_PART_PLAN.md @@ -0,0 +1,105 @@ +# Gemini native provider: observed call-part and wire identity grammar + +## Exact failed capture and source proof + +Current PR526 head eef6c202abf02489338db54c0ffbb9cb2c283ca6, tree +3f17100dcc7de10e24e635d2ee91752e8c5b7de5, is unchanged by a fresh API read. +Local a6eeb072116d390151dbefc90151ce8c8a11713b has exactly that tree. +Runtime run40405537328/job121905922854 fails after native tool_use/tool_result +and a correlated installed probe call. Provider request2 is rejected by +"Gemini part union"; native exit144 and failed terminal output remain unqualified. + +Closed native12698460531 outer SHA256 +0aba508ca5cbaebc1054a04654d6afc6b534ecdc298b91497a14857cecb03cc0 +and frontend12698965124 outer SHA256 +b107a9e30cb57e6460b5725fadf390e7ee525c4cdd4a2aea59dd754413c10151 +were checked for bounded canonical unique ordinary members, CRC and exact +committed source/tree. Raw provider-request-2.json SHA256 is +350f5d85ebcd940ea1082699ef340c1eb388bc0a5bc4157b5022829235d97b4f. +It has one model functionCall part with exactly the functionCall and +thoughtSignature fields; the signature is the literal +skip_thought_signature_validator. Both HTTP functionCall and functionResponse +IDs are uap__attempt. Native stream tool_use/tool_result IDs are +mcp_uapgeminia_inspect_runtime__uap__attempt. + +Pinned publisher google-gemini/gemini-cli@6006c14a4decfe4b891c6263ad6ad5992e404b5b +packages/core/src/core/geminiChat.ts blob095a5292c4820c8158bbb73c5af97d729e69bd87 +(SHA2567aeca2fc0eff93f003c8d628889cf6941f9359597673c907fb64d049fadd3945) +was fetched at that immutable commit and its full git-blob hash independently +recomputed. Lines111/1387-1433 define and inject that synthetic signature on the +first function call of a model turn; lines1531-1544 retain/add name__ prefixes +for native identities; lines1178/1948-1976 strip exactly name__ from calls and +responses before the outgoing provider request. Full source and provenance are +retained in /tmp/uap-shell-fresh-oct27/pinned-gemini. + +## Finite correction after two independent plan GOs + +Change only the existing provider and contract Go test files: + +1. Keep text and functionResponse part unions exactly single-key. For a + functionCall require exactly functionCall plus thoughtSignature, the exact + observed signature string, and model role. Reject missing, changed, empty, + null, wrong-type, extra-field, text/signature, response/signature or multiple + payload forms. Keep exact function ID/name/arguments and all generic strict + JSON, request/schema, request/body count and bounds. +2. Represent the two source-proven identities explicitly: retain p.id as the + existing native tool-prefixed identity and retain its issuance unchanged. + Add a separately constructed expected wire ID uap__attempt for only + provider HTTP history validation. Do not normalize received IDs or accept + either form interchangeably. Both HTTP call and response must equal the + exact wire ID; native stream checks continue to require only p.id. +3. Update inert provider exchange positives to the independently stated + observed two-key functionCall part and normalized HTTP IDs. Retain existing + foreign route/key/tool/call/result/wrapper/facts/extra-turn controls. Add + missing/wrong/malformed signature and wrong-role/extra-payload controls, + unstripped or foreign HTTP call and response IDs, and a native stream case + rejecting wire IDs even when both tool events agree. Assert the original + issued/native identity remains distinct from the expected wire identity. + +Scope is exactly repotests/agentplugins_gemini_project_native_provider_test.go, +repotests/agentplugins_gemini_project_native_contract_test.go and this plan. +No production/client adapter, source/pins, provider response, native argv/env, +authentication, permission/trust, probe/facts, stream/session/terminal grammar, +budgets, cleanup, artifact closure or qualification flags change. In particular, +the separate currently strict native stderr diagnostic guard remains strict; +this provider grammar correction alone does not claim the full attempt passes. + +## Validation and review + +After the exclusive shared Go/lint slot is granted, run the affected existing +and new inert Gemini request/provider/stream contracts and actual retained +provider-request2 replay through the exact candidate parser. An ephemeral +verification test may supply that retained JSON to the unexported parser, must +be removed before commit, and is offline parser replay, not native execution. +Run affected all-enabled lint plus the whole-file size/architecture gate and +gofmt/whitespace checks. Do not run a vendor binary locally or add a skip, +suppression, broader unknown-field allowance or qualification promotion. +Stop and report unrelated lint failures rather than expanding this plan. + +Independent implementation review precedes root-owned publication to existing +PR526. Fresh genuine source-bound native output and full applicable lifecycle +gates remain required. The failed native trace cannot be converted into a +passing terminal session by this amendment. Research diagnostics have a +separate plan and commit; no new PR, release or VS Code work is included. + + +## Actual implementation validation + +Both independent plan reviews (root and CLI) approved original plan SHA256 +4785cc2654ab6a7940f6f95a22a651c492c12736a054980484d84a5b33281441 +before implementation. Both independent code reviews approved the exact final +provider SHA13081532237a89b364d1cc667f9148716d2f0efaf3f1932f6e00e34feb66929f +and contract SHA4b50a01322cebd24e28f6bcdd903277c37b39289483ba9d37c26bf02bfb852eb. + +The affected inert Gemini contracts plus the exact retained native request2 +replay pass in0.013 seconds. The temporary offline replay test verified its +fixed SHA256 and one call/one response, then was removed before final source +checks and commit. It did not execute Gemini. The initial affected lint found +one test-only staticcheck QF1003; the equivalent tagged switch received both +independent final GOs. Its focused provider cases pass in0.011 seconds. Final +all-enabled affected lint and whole-file size/architecture gate each report +zero issues; gofmt and whitespace checks are clean. No vendor binary ran. + +The separate research correction remains its own plan/code history. Fresh +genuine native execution, unchanged native stderr/session/terminal checks and +applicable full lifecycle proof remain required; no flag is promoted here. diff --git a/docs/GEMINI_PROJECT_NATIVE_STARTUP_METRICS_DIAGNOSTIC_PLAN.md b/docs/GEMINI_PROJECT_NATIVE_STARTUP_METRICS_DIAGNOSTIC_PLAN.md new file mode 100644 index 000000000..dd7ff6661 --- /dev/null +++ b/docs/GEMINI_PROJECT_NATIVE_STARTUP_METRICS_DIAGNOSTIC_PLAN.md @@ -0,0 +1,302 @@ +# Gemini: exact measured startup-metrics diagnostic tuple + +## Fresh native progress and still-failing strict guard + +Published PR526 aaf2156beceac7947954297f0afb50e84a43c7d3/tree +d9918701fdbc8f10bfa3dba589884b91573aaa2d contains the reviewed held explicit +HOME/target expectation correction. Genuine runtime40468040506/job122068455782 +now returns native exit0/error=false/context_error=false, provider_returned=true +and exactly two strict provider routes, without provider_error. This is actual +progress beyond the prior fact mismatch; it is not full admission or lifecycle +qualification. The test stops at the unchanged native stderr guard before +Gemini stream/session/result admission. All five qualification flags, real +model/vendor authentication and runtime_attempt_complete remain false. + +Native12717562120 outer SHA256 +e088fe43802d72da19e81e833f350365bea2777332fe9abe61bd0a88ab2147bc, +innerbcbb5a45e47614ef8a30136d3baec990e4ab1aad3a5eabe6cd65757d609cd238 +has21 members. Frontend12717218227 outer SHA256 +404882ceddf59a638e8dbf92ca6eeda6bf370a64d04366aa2120001eeb9f72af, +inner5b1f3d0ddcf76d1abda803cf86fa74a38d996a14ef0db234ec898d84cc61a868 +has25. Both are API-hash matched, bounded canonical unique ordinary ZIP/CRC +checked; exact source/tree/empty clean-source streams and all24 frontend +command-stream byte/hash joins were independently verified. Raw data and +finite summary remain in /tmp/uap-shell-fresh-oct27 (gemini-aaf-native-audit.json). + +The successful native command's exact419-byte stderr has SHA256 +315efcf74c381fe9f43bc921c84091ca24436a267b3bfcd76b5c705089309c7f. +It is the previously measured342-byte TERM=dumb/256-color/ripgrep tuple, +followed by exactly77 bytes: + +```text +[STARTUP] Phase 'cleanup_ops' was started but never ended. Skipping metrics. +``` + +The suffix SHA256 is +90f4d39b0bfd110628b068fb3fa37db1952aeb79d77f8dca50334b4922a325b1. +The current contract deliberately rejects this then-unobserved combination; +this plan records the new actual observation before amending that expectation. +No former failed capture will be relabelled. + +## Exact immutable source meaning + +At google-gemini/gemini-cli@6006c14a4decfe4b891c6263ad6ad5992e404b5b: + +| Source | Git blob | Full-file SHA256 | +| --- | --- | --- | +| packages/core/src/telemetry/startupProfiler.ts | 260952eb032a380649d94956aa00cc65d88026a8 | d785e9e60e3f025c33f9035c2968e25873f8eabbe7d83228eb4c8ce593d0a6cc | +| packages/cli/src/gemini.tsx | a14a8b8dd99b501efceab5bcaa5794ed5176eb82 | 72410f158bcd7a75c9654a8bfffba34daba3cc79f1e4bcf15cb09c98e848aa0c | + +Complete files were fetched, full SHA256 and git-blob identities recomputed +and retained under pinned-gemini. gemini.tsx507–518 starts cleanup_ops and +launches Promise.all of checkpoint/tool-output/background-log cleanup without +awaiting it. Its catch logs the separate 'Early cleanup failed:' error; its +finally ends the performance phase. After config.initialize(), noninteractive +startup calls startupProfiler.flush at925 without awaiting that earlier +promise. StartupProfiler.flush emits the precise warning for each phase not +yet ended, skips that phase's performance metrics, then clears phase records. + +The warning states that this performance phase had not ended when startup +metrics were flushed. It does not itself establish a cleanup error or later +cleanup success. Do not infer either from it. Independent external process +supervision and all existing fatal cleanup/exit/context/capture checks remain +mandatory; the different 'Early cleanup failed:' diagnostic remains refused. + +## Finite amendment after two independent plan reviews + +Scope only repotests/agentplugins_gemini_project_native_contract_test.go, where +the existing stderr helper and its contracts live, plus this plan. Add one +whole-string case: the exact419-byte measured combination. Keep the existing +empty/ripgrep/342-byte cases. Do not admit the77-byte suffix alone, an optional +suffix or prefix rule, a regex, another phase, reordered/duplicate/control/CRLF +bytes or extra metrics/API/auth/stack/cleanup errors. + +The original helper call remains at the same point AFTER f.command has +required successful native exit, no context/process/capture/cleanup error, +and BEFORE every strict provider/native-stream/session/probe check. Do not +change command env/argv, supervision, source pins, owned data/profile or +public installation receipts. Preserve the captured raw streams unchanged. +No state/qualification gate or provider/protocol grammar is widened. + +## Meaningful inert checks and publication + +Independently state the419-byte literal and its full digest. Move only this +new measured whole tuple out of the prior negative matrix and into positive +coverage; add suffix-alone, changed phase, Early cleanup failed, unknown +metrics, extra/truncated/reordered/CRLF/duplicate/API/auth/control variants as +strict negatives. Existing original342 positives and old1952-byte failed +private-stream refusal remain. + +Replay actual aaf419 bytes against the helper and actual native stdout through +the existing strict stream validator, with held nonce/root/data/HOME/marker +and captured independent probe events. If a subsequent stream guard fails, +report that measured boundary and retain it; do not fold a grammar correction +into this slice. Run focused Gemini inert contracts and retained replay, +actual affected all-enabled plus unfiltered six-linter gates in the exclusive +slot, gofmt/diff checks and two independent code reviews. No vendor process +or hosted eligibility spoof runs locally. Root alone publishes to existing +PR526 with a fresh ref/tree check. Fresh genuine complete native and separate +full user/A/B lifecycle evidence remain necessary before qualification. +No release/new PR or VS Code work. + +## Implemented and recovered validation + +Independent CLI and desktop plan/code reviews approved the exact whole-tuple +amendment. Reviewed contract SHA256 is +371aab6e68a99b701c4bc5e5c2c0bbb8e563b916f0b300d10c1d84b65c6bcf19. +After workspace replacement, this source file and the original plan were +restored byte-for-byte; both original hashes and source-review GOs still match. +The exact raw archives and pinned full sources were re-downloaded and verified. + +Fresh ^TestGeminiProjectNative contracts and an offline full actual aaf native +stream/probe replay passed in0.016s. The replay held seven independent member +hashes, original installed literals, receipt target/data, original HOME/root, +nonce, successful captured command and constructed native call/sentinel IDs. +It admitted the actual419-byte diagnostic and complete captured init/user/ +tool-use/tool-result/assistant/result stream through unchanged strict validators, +including independent initialize/list/call probe-event facts and PID/session +joins. No subsequent grammar amendment was needed. The retained original +runtime_attempt_complete=false and all five false flags were explicitly checked. + +The temporary replay file was removed before both lint gates and is absent +from the committed tree. Actual all-enabled affected lint against recovered +pland57d2f83 and the unfiltered whole-file six-linter gate each reported zero +issues. Source formatting and whitespace checks pass. No vendor/installer, +HTTP listener, native child or positive hosted guard ran locally. Fresh genuine +execution on this corrected source and the separate full lifecycle remain +required; offline admission does not relabel the actual failed aaf capture. + + +# Gemini: exact measured cleanup start-mark diagnostic tuple + +PRE-CODE proposal. Obtain root and one independent GPT-6.1 Sol xhigh PLAN GO +before implementation. Read AGENTS.md, PROJECT_INSTALL_OWNER_SCOPE.md and the +capability-preservation contract. Root owns Git and GitHub mutations. This is a +bounded diagnostic correction on existing PR526, with no VS Code work or release. + +## Exact new genuine evidence and limits + +Published source239067ed7e28d2d248988092dbdd34070e2c8b87, tree + a02f200ed86d19a74e6452d4253f1a0beb969cff. Current hosted runtime40587214352, +Gemini job122496469936 completed failure2026-10-27T22:23:06Z. Source/build clean, +all24frontend stream joins and57nested stream joins, API/ZIP ordinary closed +membership/CRCs, official Gemini/Node/scanner pins and complete runtime file +closure, public source/package/installation/binding/data/physical/receipt IDs, +five exact catalogs and eight probe segments independently join. + +Native artifact12775253240 has27members, outer137439B SHA256 +3dacba1aae28f1b2831de695845a2ad59e9bdd399a4209d2f0d4e1128608d345; +inner SHA256c7c15fcd5b66312c666094c2bee1a7ae37fe64db90ad31e2798518be1ae30e5c. +Frontend12775283254 has25members, outer53590B SHA256 + a03c9b3443ce82819e34d895fea7658cc45c114e79ddbc380381479fc80282d0; +inner SHA256f94bbbae306e54730bc5971fbec1318ba51f2a4a5fd69df68bac42cd75020e3f. +Independent failed-only RAW GO: +/tmp/uap-gemini-239-current-40587214352/raw-audit.json SHA256 +138c196e0277a6c174780ddf3bb50a54777fa11d4698af1e616942ad079b76b6. + +The earlier finite listing correction admits installed-user and installed-a +catalogs with exact foreign/builtin/owned rows. The user native stage completed +its independently joined scripted call/result. At native:installed-a, every +recorded public/native command still exits0 without error/context failure and +ordinary full-descendant supervision; last native lasts1597ms. Its two provider +requests/responses and selected A tools/call facts/native result independently +join. The fixture refuses before native stream acceptance at the unchanged +`Gemini cycle unknown native stderr` guard after20698ms total. Provider-completed +prefix remains baseline-a,installed-user; whole-cycle provider closure is +incomplete and fatal. No later lifecycle is observed. Allfive/native-complete/ +authentication/model flags remainfalse. Neither this raw review nor the proposed +correction relabels that failed capture or promotes qualification. + +The exact541-byte native stderr is the existing419-byte terminal/ripgrep/ +cleanup-unended tuple followed by exactly this122-byte newline-terminated line: + +```text +[STARTUP] Cannot measure phase 'cleanup_ops': start mark 'startup:cleanup_ops:start' not found (likely cleared by reset). +``` + +Full541B SHA2564a44629c8b644a0e5629b463e0fc14392bda3ef65c08cca2e0cd8963ff59d3c2. +Suffix122B SHA2562bc542b67a6f3474557140033c8830144135651234852ee38e78b9b4aa32a01a. +The existing419B tuple remains SHA256 +315efcf74c381fe9f43bc921c84091ca24436a267b3bfcd76b5c705089309c7f. +No ordinary MCP log allowance is proposed: the measured problem is this distinct +performance warning, while the inspected headless log suppression remains intact. + +The inherited Cline job122496469791 succeeds at this exact239 source. Separate +independent raw audit closes54native/31frontend members,30frontend/130nested +joins, all complete matrices and allfive flags with auth/modelfalse: +/tmp/uap-gemini-239-current-40587214352/cline-independent/raw-audit.json SHA256 +da2f41c992942c512e5207e3e40d786fdb05ab0f2b62e88c7192bf1ff8dd47c2. +That does not qualify the failed Gemini capture. + +## Exact immutable primary-source meaning + +Official google-gemini/gemini-cli commit +6006c14a4decfe4b891c6263ad6ad5992e404b5b source membership and full bytes were +freshly verified through GitHub Contents API and recomputed Git blob/SHA256: + +| Source | Git blob | Full SHA256 | +| --- | --- | --- | +| packages/core/src/telemetry/startupProfiler.ts | 260952eb032a380649d94956aa00cc65d88026a8 | d785e9e60e3f025c33f9035c2968e25873f8eabbe7d83228eb4c8ce593d0a6cc | +| packages/cli/src/gemini.tsx | a14a8b8dd99b501efceab5bcaa5794ed5176eb82 | 72410f158bcd7a75c9654a8bfffba34daba3cc79f1e4bcf15cb09c98e848aa0c | + +Receipt /tmp/uap-gemini-239-current-40587214352/startup-warning-primary-source-receipt.json +SHA256683d5e8ae0f3c312d042ae422e0f1d414933821fe95bcf306f873de344115969. +Source/main and profiler bytes are retained with API receipts beside actual raw. + +Main507 starts cleanup_ops and launches the cleanup Promise.all without awaiting +it. Its catch emits a separate Early cleanup failed diagnostic; its finally ends +the captured phase handle. Main925 flushes startup metrics after configuration +initialization. Profiler.flush warns for an unfinished phase and skips its +metrics, then clears all tracked performance marks/measures/phases. The captured +handle can later reach _end; if its start mark is absent, _end emits precisely the +new Cannot measure line, marks that captured phase ended and returns. This is a +source-defined performance-measurement refusal. The warning alone proves neither +an actual cleanup error nor later successful cleanup, and does not replace any +independent subprocess/descendant/provider/profile closure. + +## Smallest finite implementation after both plan GOs + +Create an isolated agreed-current239 checkout after root's fresh remote-head +check. Root first commits this accepted amendment to the existing +`docs/GEMINI_PROJECT_NATIVE_STARTUP_METRICS_DIAGNOSTIC_PLAN.md`, preserving all +previous plan/validation/evidence. If the remote moved, preserve concurrent work +and obtain exact source reconciliation before code. + +Limit the code change to +`repotests/agentplugins_gemini_project_native_contract_test.go`, the existing +whole-string stderr helper and its dedicated inert contracts. Add exactly one +new whole-string accepted case: existing419B tuple plus the literal122B suffix +in that measured order. Preserve all four current accepted whole-string cases +and all existing hostile/malformed controls. Do not use a regex, prefix/suffix +matching, normalization, optional warning, phase parameter, reordered tuple, +blank line, duplicate or any unmeasured combination. The122B suffix alone and +the342B terminal tuple plus only the new122B suffix remain refused. + +Preserve the helper's exact caller position after successful bounded native +command execution and ordinary full-descendant cleanup, before strict provider/ +stream/session/probe and all owned data/profile/source checks. Complete caller +files `agentplugins_gemini_cycle_observe_test.go` and +`agentplugins_gemini_project_native_attempt_test.go` remain byte-identical. +Retain the unknown-stderr fatal, process/exit/context/capture/deadline checks, +whole provider closure and fixed finite lifecycle/prefix matrix. Keep every +production adapter/provider/classifier, public installation command and receipt, +config/cache/metadata/no-follow/foreign/owned profile authority, Python admission, +workflow/source selection, immutable pins, environment/argv and credential guard +unchanged. No subprocess, fixture lifecycle or native behavior is added. + +## Meaningful independent verification + +A new literal whole541B golden contract independently asserts length541 and full +SHA2564a44629c..., plus suffix122B/SHA2562bc542b... . It accepts only this newly +measured full tuple. Negative controls include suffix alone, existing342B terminal +plus new suffix only, wrong/mismatched phase or start-mark name, reversed last two +lines, duplicate suffix/full tuple, missing final LF, added leading/trailing LF, +CRLF/control/ANSI/NUL bytes, altered warning text, and appended unknown metrics, +auth/API/stack or Early cleanup failed error. Keep all original419B/342B/empty/ +ripgrep positive and negative tests unchanged. + +Two independent exact implementation CODE reviews follow. Under the serialized +slot run focused Gemini/shared inert Go, existing Gemini/cycle/runtime Python +contracts, actual affected full-root all-enabled and unfiltered six-linter gates, +gofmt and whitespace. Re-admit original239 failed27member archive under both its +exact-source and candidate readers and assert native member/summary bytes remain +identical and whollyfailed/allfalse. Re-admit the exact239 inherited Cline success +separately without changing its meaning. Verify the complete unchanged caller +file hashes and that only the authorized contract file changes among code. +No local vendor/native/scanner/public installer executable runs. Root alone +publishes a reviewed normal expected-head fast-forward to existingPR526 after +executed gates. Only its resulting new genuine capture can establish further +native/lifecycle progress; no retry at unchanged source or future allowance is +authorized by this amendment. + +## Accepted missing-start-mark amendment before implementation + +Exact draft SHA256 `9c507df654a4b2cd0a2a86c3e55f7f350818a2249e426c4a6ce255ab26b77f81` +received independent PLAN GOs from root and GPT-6.1 Sol xhigh `native_e2e_finish` +before any code edit. Receipts SHA256: +`f84ddfb12880979598ac68627e950c16719eb76c4bf0d230af3715381e7d02b1` and +`1e9f70803ac0ebb53b395880a8a5c1ac1379690751cfccd925347e498e0107ed`. +Both independently reverified actual541B/prefix419B/suffix122B hashes, official +Git blob/source bytes and the preserved strict caller positions. Root freshly +checked PR526 remains239 before creating this isolated checkout. + +## Exact missing-start-mark implementation and executed gates + +Code `2f67eac62185d52ef4aa51704da088924e753b17`, tree +`d7bb418dcfb143ac7343102da59ec903f768c5d0`, received independent root and +`native_e2e_finish` CODE GOs. Receipt SHA256s: +`ac84195d4fb9cba90ce844c68d938ada5e0aa1511612c7e1d3b7255a1fc7ec01` and +`52ef6c112ea543304b4d25c2026280bb34e46a12eabeee49b39f5fbdfece2f6c`. +Only one contract code file changed: exactly one541-byte tuple, independent +541/122-byte hashes and18 hostile variants; every previous byte outside these +additions and both complete callers remain preserved. + +Executed focused Gemini/shared inert Go PASS1.175s;62Python contracts PASS; +full-root affected all-enabled and unfiltered six-linter gates both zero issues. +An initial default-sandbox process/socket prerequisite failure is retained; the +unchanged exact suite passed with ordinary loopback/process capabilities. No +vendor/client/scanner/public installer binary was run locally. Original239 +Gemini27-member failed archive and inherited Cline54-member successful archive +re-admit with all raw members and summaries unchanged; replay receipt SHA256 +`73e547a8bdff2883b5321eedf2df67c06dc86bb629c5818fc7600d70b0629c64`. +Current Gemini remains unqualified until a new exact-source genuine hosted pass. diff --git a/docs/GEMINI_PROJECT_NATIVE_TERMINAL_DIAGNOSTIC_PLAN.md b/docs/GEMINI_PROJECT_NATIVE_TERMINAL_DIAGNOSTIC_PLAN.md new file mode 100644 index 000000000..b9cadbae3 --- /dev/null +++ b/docs/GEMINI_PROJECT_NATIVE_TERMINAL_DIAGNOSTIC_PLAN.md @@ -0,0 +1,100 @@ +# Gemini installed native stderr: exact measured terminal prefix + +## Source-bound observation + +Current published PR526 sourcec887f66df1893aff40deda0012d869afa74af7b3 has +tree d3f155960cb42efafe31d6a8ef15ecbb63a72572, identical to reviewed local +4eced02fbb7e490f1be8662202311b680fe18426. Preserve both newly published +provider-part/wire-ID and research refresh corrections and their history. + +Earlier genuine run40405537328/job121905922854 at eef6c202/tree3f17100d +captured the native installed attempt's stderr in closed artifact12698460531 +(outer SHA2560aba508ca5cbaebc1054a04654d6afc6b534ecdc298b91497a14857cecb03cc0). +Its first342 bytes are exactly these three newline-terminated ASCII lines: + +```text +Warning: Basic terminal detected (TERM=dumb). Visual rendering will be limited. For the best experience, use a terminal emulator with truecolor support. +Warning: 256-color support not detected. Using a terminal with at least 256-color support is recommended for a better visual experience. +Ripgrep is not available. Falling back to GrepTool. +``` + +SHA256 of exactly those342 bytes is +0309ffcd9f9558b019117eab516a089bfe80be8c1a596be48e3794ecf695a953. +The complete1952-byte failed stderr has SHA256 +2f4e54c8fc557813d6b32779523c8daed46e8484b1afee9ae5556049b21e51c0 +and contains additional startup cleanup metrics and an API error/stack. That +full failed stream is not an admitted diagnostic and must remain refused. + +Pinned google-gemini/gemini-cli@6006c14a4decfe4b891c6263ad6ad5992e404b5b, +packages/core/src/utils/compatibility.ts blob47ef078831255119ded71fa972929408dabee801 +defines isDumbTerminal for TERM=dumb/vt100 and emits the exact basic-terminal +and256-color warning messages in that order. The entire immutable file was +fetched and its full git-blob hash recomputed; provenance is retained under +/tmp/uap-shell-fresh-oct27/pinned-gemini/compatibility-audit.json. +The UAP fixture's unchanged nativePlatformEnvironment supplies literal +TERM=dumb; f.env also supplies NO_COLOR=1. This plan does not choose a new +terminal, install ripgrep or change that environment to hide the warnings. + +## Finite guard amendment after two independent plan GOs + +Change only repotests/agentplugins_gemini_project_native_attempt_test.go and +repotests/agentplugins_gemini_project_native_contract_test.go, plus this plan. + +Factor the existing native diagnostic guard into a small exact-byte helper. +Keep its currently admitted empty stderr and exact ripgrep-only string. +Admit exactly one additional whole byte string: the measured342-byte three-line +tuple above. Do not use HasPrefix, trimming, substring/regexp matching, line +filtering, arbitrary terminal values or combinations of warnings. + +The helper is called only at the same existing point, after the unchanged +f.command has independently required exit0, no process/capture/context error, +bounded stdout, no omitted stderr and strict descendant cleanup. Preserve that +call ordering and the fatal diagnostic refusal. A nonzero exit, provider/API +error, native/probe/stream/session/sentinel mismatch or failed cleanup cannot +be converted into success by recognizing these benign bytes. + +Inert contracts independently state and hash the observed342-byte literal and +verify exactly the three admitted strings. Reject truncated/CRLF/reordered/ +duplicated/extra-newline/extra-prefix variants, either terminal warning alone, +the two terminal lines without the ripgrep fallback, TERM=vt100 or changed +messages, appended startup metrics, API/stack/authentication diagnostics, +embedded NUL/ANSI controls and the recorded failed stream's additional lines. +No diagnostic is removed or normalized in the retained native artifact. + +Scope excludes all production code, provider and research grammar, pins, +native arguments/environment, source/installed identity, auth/trust/permission, +original budgets, process supervision/cleanup, output closure and qualification +flags. Useful source remains preserved; VS Code is excluded. This does not +establish that the newly corrected native attempt completes. + +## Validation, review and remaining genuine proof + +Use only the root-granted exclusive Go/lint slot for affected inert native +diagnostic/provider/stream contracts and both actual affected all-enabled and +whole-file size/architecture lint. Replay the retained failed1952-byte stderr +offline through the helper and require refusal; any temporary replay test must +be removed before commit. Run gofmt and whitespace checks and obtain independent +code reviews before root-owned publication to existing PR526. No vendor binary, +new PR or release is included. + +Fresh genuine source-bound execution must still pass the exact provider +exchange, native stream/session/sentinel, probe/installed authority joins and +cleanup. The full applicable project lifecycle remains a separate mandatory +proof. All unproved qualification, vendor-authentication and real-model flags +remain false; the old failed trace is never relabelled. + +## Completed local validation + +Both independent plan and code reviews approved the final two-file correction. +The exact helper resides alongside the existing native stream helper in the +contract file, retaining the attempt file's prior size. The affected diagnostic, +provider, stream, identity and artifact contracts passed (0.015s), including a +temporary offline replay of the exact retained1952-byte stderr by full hash. +That actual failed stream was refused while its exact measured342-byte tuple +was admitted; the temporary replay test was then removed. Actual affected +all-enabled lint and unfiltered whole-file size/complexity/architecture lint +each reported zero issues. Formatting and diff whitespace checks passed. +Checks used the granted exclusive slot, pinned Go1.26.10 with Go1.22 source +compatibility, private shared-memory temporary/lint directories and existing +bounded module/build caches. No vendor, installer, hosted guard or model ran +locally. The fresh genuine hosted result remains a required separate proof. diff --git a/docs/GEMINI_PROJECT_RESEARCH_MCP_STDERR_PLAN.md b/docs/GEMINI_PROJECT_RESEARCH_MCP_STDERR_PLAN.md new file mode 100644 index 000000000..24a24be4d --- /dev/null +++ b/docs/GEMINI_PROJECT_RESEARCH_MCP_STDERR_PLAN.md @@ -0,0 +1,102 @@ +# Gemini research: retain a strict MCP inventory emitted on stderr + +## Actual next read-only research boundary + +At current published9f81687411249640a11a54650888cec76c4820d5/tree77539fdb, +research40459797394/job122045257739 genuinely passes the already reviewed +configured-a-skills command with its exact149-byte refresh diagnostic. Its +next configured-a-mcp command exits0/error=null, stdout0, stderr201 bytes with +SHA25613b38cbfb721679de46a7ab935acc81b597c8a34c10ea57fa21b77d45c6ea595: + +```text +Configured MCP servers: + +⛔ uap-gemini-research-user: http://127.0.0.1:9/uap-gemini-research-user (http) - Blocked +⛔ uap-gemini-research-a: http://127.0.0.1:9/uap-gemini-research-a (http) - Blocked +``` + +This is the existing exact configured-inventory grammar and held fixture +user/A endpoint/status selection on the other capture channel. It is not an +API error, connection success, authentication or MCP protocol observation. +The present _probe guard admits only the measured empty MCP sentinel on +stderr and therefore refuses this nonempty inventory before parse_mcp. + +Artifact12714503565 outer SHA256 +a748f4a7e5d5598ede70c49a78856a14ec5a2bc080fe7f34d976b8bca9a4cef3, +inner9eba023849b74053f7bff21d3c6d19024c4f922efd93d201f411f18864e20edc, +has39 canonical unique ordinary members with verified CRCs. Exact source/tree, +clean source streams, all38 command-stream byte/hash joins and all-false +qualification flags were independently checked. collection_complete=false +remains truthful for this original refused capture. + +## Pinned source and existing strict parser + +At pinned google-gemini/gemini-cli@6006c14a4decfe4b891c6263ad6ad5992e404b5b, +packages/cli/src/commands/mcp/list.ts blob0282277557e9b5d332e7eefe0fe5a564cfd521aa +(SHA2569342947a76d664b1d15894ef1f41d53b1251641219458bfb59193fc83fb8da37) +emits the header and each exact status/endpoint row through debugLogger.log. +debugLogger.ts blob9c5a82c12397893c199131418288316a48a24959 delegates to +console.log. ConsolePatcher.ts blobddd26fca0bc9a87dd4e9a11744d252a890d37055 +and gemini.tsx bloba14a8b8dd99b501efceab5bcaa5794ed5176eb82 route these console +events through the output listener to stderr in the observed CLI command path. +All full files were fetched at the pin; recompute and retain their git-blob +identities before implementation. This source supports channel selection, +not a new MCP listing grammar or arbitrary warning acceptance. + +The existing parse_mcp already strictly decodes bounded captured bytes, rejects +unknown controls/rows/duplicates and validates the finite indicator/status +pair. The caller immediately applies _require_mcp against exactly the held +user/A/B names, original port9 endpoints and expected Blocked policy, plus the +existing untrusted-folder warning/trust assertions. Preserve every such check. + +## Finite channel correction after two independent plan GOs + +Scope is scripts/project_native_collectors/gemini.py, its existing inert test +module and this plan. Only the exact (mcp,list) command may select stderr as +its inventory, and only when stdout is exactly empty and the complete stderr +passes the unchanged parse_mcp grammar as a nonempty inventory. Validate the +unchanged exact record exit/error types and byte streams before considering +this branch. Keep both original channels in evidence unchanged. + +No line filtering, partial-prefix match, ignored warning, merge of both streams, +strip of foreign diagnostics or general stderr allowance. The existing empty +MCP stderr sentinel, valid stdout inventory and exact ripgrep/skills refresh +rules retain their existing meaning. Preserve only the parser's exact existing +_UNTRUSTED warning pair under the current caller's unchanged trust assertions; +it is part of the already admitted inventory grammar. Doubled-channel output, +malformed or foreign stderr, appended auth/API/stack text and any unknown or +noncanonical warning prepended to a configured inventory fail. A syntactically +valid foreign name/URL/status still +fails the caller's exact selected-scope policy checks. All owned authored file +byte/mode/alias preservation checks run before returning the chosen inventory. + +Inert tests use the independently stated actual201-byte literal and digest, +complete collect() configured/user/A/B/untrusted fixtures with stderr-only +inventory, and hostile wrong command/record type/stdout/type/control/duplicate/ +extra diagnostic/foreign row/endpoint/status cases. Exercise actual parser and +full source-selection checks, not a replacement grammar. Verify original +authored private config/skill/trust preservation negatives remain meaningful. +Replay the retained actual201-byte response through the parser and expected +held user/A Blocked selection; the old incomplete artifact stays incomplete. + +Run the existing complete Gemini research Python test module, AST/diff checks +and two independent code reviews. No Go/native/vendor/positive hosted guard is +needed. Root-only publication to existing PR526 follows a fresh real ref/lease. +Fresh genuine research must complete all remaining stages before claiming a +complete read-only observation; it grants no runtime/MCP/auth/model/lifecycle +qualification. Those source-bound native cycles remain separate obligations. +No source pin, trust/permission policy, new process, release/new PR or VS change. + +## Completed local validation + +Both independent plan and complete code reviews approved the exact two-file +channel correction. The complete Gemini research module passed all25 tests +(0.129s), including full user/A/B/untrusted discovery, exact literal/hash, +capture/channel/parser refusal and authored-file mutation controls. Independent +root rerun also passed25 tests (0.116s). The exact retained201-byte stderr and +its original successful command receipt replay through the actual _probe, +parse_mcp and held user/A Blocked selection passed; the old incomplete archive +was left unchanged. Both Python ASTs and diff whitespace checks passed. +No Go, vendor, native client/model or positive hosted guard was executed. +Fresh genuine completion of the remaining research stages is still required; +none of this source observation establishes runtime or lifecycle qualification. diff --git a/docs/GEMINI_PROJECT_RESEARCH_REFRESH_DIAGNOSTIC_PLAN.md b/docs/GEMINI_PROJECT_RESEARCH_REFRESH_DIAGNOSTIC_PLAN.md new file mode 100644 index 000000000..59b6f7619 --- /dev/null +++ b/docs/GEMINI_PROJECT_RESEARCH_REFRESH_DIAGNOSTIC_PLAN.md @@ -0,0 +1,79 @@ +# Gemini research: exact measured MCP-refresh stderr + +## Observed failed boundary + +Current PR526 eef6c202abf02489338db54c0ffbb9cb2c283ca6/tree +3f17100dcc7de10e24e635d2ee91752e8c5b7de5 has research run40405537349, +job121908899835. Closed artifact12698121032 outer SHA256 +bd87b584e3067a0a5b8008fcb2d4750dde652dd2e3692893a93390e6b481ae7b +was checked for bounded canonical unique ordinary ZIP members, CRC and exact +source/tree. The first configured-a-skills probe runs the existing exact +skills list --all command, exits0 with explicit null capture error, stdout1214 +bytes and stderr149 bytes. Existing source parsing is blocked by the stderr +guard before the actual configured listing is validated. + +The exact stderr bytes (SHA256627ecbbc677b2ca1e37a8b6894cd23619ddcf0ab7e1b1c16bdc460229c434234) +are the already admitted 52-byte ripgrep fallback followed by exactly these +ASCII bytes (each displayed line ends with one newline): + +```text +Scheduling MCP context refresh... +Executing MCP context refresh... +MCP context refresh complete. +``` + +No later configured or untrusted +native research probe was observed in this failed run. + +## Finite amendment after two independent plan GOs + +In scripts/project_native_collectors/gemini.py retain the whole existing +exit/error/stream type checks first. Admit one additional exact stderr byte +string: the measured 149-byte concatenation, only for the exact +('skills', 'list', '--all') operation. Do not admit it for mcp, version/help, +another argv, partial/reordered/duplicated lines, other bytes or a prefix plus +extra diagnostics. Keep the existing empty-MCP sentinel and fallback-only +tuples unchanged. Preserve stdout bytes and existing strict skills parsing, +exact selected source/path/enablement checks, trust/exclusion controls and +post-command authored-file checks. No stderr stripping, broad pattern, +diagnostic normalization or auth/error acceptance is allowed. + +In scripts/test_project_native_gemini.py add an independently stated literal +positive and mutated/truncated/CRLF/reordered/duplicated/appended/foreign-command +negative cases, plus nonzero exit, bool exit, missing/non-null error, wrong +stream types and authored-file mutation refusal. Exercise the actual full +inert collector with this tuple at configured-a-skills while retaining its +existing complete call inventory and false runtime/MCP/auth qualification. +Test that malformed/cross-project stdout still fails after the exact stderr +tuple is admitted; diagnostics alone cannot qualify source selection. + +Scope is these two existing Python files and this plan. Do not change source +pins, host/profile, native invocation, 30-second command limit, collector +budget, trust/excluded MCP configuration, process cleanup, artifact admission, +case meanings or qualification requirements. No native binary runs locally. +This plan is separate from the provider call-part/wire-ID grammar correction. + +## Validation, review and remaining proof + +Run only the affected existing/new inert Gemini collector contracts and shared +research contracts needed to verify unchanged envelope admission, plus syntax +and whitespace checks. No Go/lint slot is needed. Independent code review +precedes root-owned publication to existing PR526; no new PR or release. + +The future genuine run must actually execute all remaining A/B/user/untrusted +operations and preserve exact source-bound raw evidence before their cases can +pass. Inert success or this old failed capture does not establish new native +observations, a runtime lifecycle, MCP exchange, vendor authentication or model +behavior. All unproved qualification flags remain false. VS Code is excluded. + + +## Actual validation + +Both independent plan reviews (root and CLI) approved SHA256 +71a06dd903b535c632412a1f1a2c7301d8ade1783899c9486b8f9141d4f7994f +before implementation. The actual affected Gemini collector and shared research +inert modules pass all31 tests in0.388 seconds. Python AST and whitespace checks +pass. The positive literal independently matches the captured149 bytes and +SHA256; hostile command/byte/capture/source-path/authored-mutation cases remain +refused. No vendor or Go binary executed. Fresh genuine hosted observation is +still required for every remaining native probe. diff --git a/docs/GEMINI_PROJECT_RESEARCH_UNTRUSTED_SKILLS_DIAGNOSTIC_PLAN.md b/docs/GEMINI_PROJECT_RESEARCH_UNTRUSTED_SKILLS_DIAGNOSTIC_PLAN.md new file mode 100644 index 000000000..295101209 --- /dev/null +++ b/docs/GEMINI_PROJECT_RESEARCH_UNTRUSTED_SKILLS_DIAGNOSTIC_PLAN.md @@ -0,0 +1,111 @@ +# Gemini research: exact measured untrusted-skills diagnostic tuple + +## Current source and actual newly reached guard + +Published PR526 d94270ce98463ecb2060b49df0445e7d19e5e733 has tree +dbfe7549a77f3cbd25e9569a5d27758f9470faf2, matching reviewed local6eaff039. +Preserve the newly published strict stderr-only MCP inventory channel and all +earlier exact refresh/provider/native diagnostic corrections. The separate +native expected-env slice remains separate; no native outcome is claimed here. + +Genuine research40465927279/job122061320882 now passes configured A, B and user +MCP inventory with their exact scope/endpoints/Blocked state. Its next +untrusted-a-skills command exits0/error=null, stdout1029 bytes with the same +user-only skill inventory, and stderr211 bytes SHA256 +90f97337101f629e2177832ecdca61c30015861ed2358dffeceb640a894d917b. +The guard refuses this previously unknown complete diagnostic tuple: + +```text +Skipping project agents due to untrusted folder. To enable, ensure that the project root is trusted. +Ripgrep is not available. Falling back to GrepTool. +Project hooks disabled because the folder is not trusted. +``` + +Artifact12716448810 outer SHA256 +89adb7a0bc92ea79f92d569a1ab8f8c0954ef35fcb0e69165d522c62b3979fa8, +inner45d9dc073db18fba47a3c3bfea5c9f5ba41ab6ced47522bd9f884636338a9875, +has49 canonical unique ordinary ZIP members with verified CRCs. Root verified +exact source/tree/clean streams and all48 command stream byte/hash joins. The +actual211-byte stderr was also independently re-read/rehashed locally. The +original incomplete/all-false capture remains unchanged. + +## Immutable source support and policy meaning + +At pinned google-gemini/gemini-cli@6006c14a4decfe4b891c6263ad6ad5992e404b5b: + +| Source | Full git blob | Full-file SHA256 | +| --- | --- | --- | +| packages/core/src/agents/registry.ts | 267e13b07563757a42a97b7467b6607b9072ec0e | 2355cb83fe89e6299a64f7208f1cc316a6150f4ca0ecf1352489ef1a693f1f58 | +| packages/core/src/hooks/hookRegistry.ts | 1dad67bad5414e8fd06f0499c1b8a53e1b4ae048 | 1e79ac1bb97cf1144ace5aa449cd06d400543f4292e97eeead4d6e0618e47614 | + +Full files were fetched and git-blob identities independently recomputed, +retained in /tmp/uap-shell-fresh-oct27/pinned-gemini. Agent registry emits the +first exact message instead of loading project agents when folder trust is +enabled and the project is untrusted. Hook registry emits the third exact +message instead of processing project hooks when untrusted. The middle exact +ripgrep message is the previously source/native-observed fallback diagnostic. +These are truthful restrictions of the deliberately untrusted control. They +are not permission grants or reasons to load suppressed project components. + +## One exact stage/command/byte amendment after two independent plan GOs + +Scope: scripts/project_native_collectors/gemini.py, its existing inert test +module, and this plan. At the existing _probe stderr guard, add exactly one +whole byte-string allowance, and only when label is untrusted-a-skills and +arguments are exactly (skills,list,--all). Keep original successful integer +exit0, explicit error=null and exact byte-stream type checks before it. + +No trimming, prefix/line/regex filtering, generic untrusted-warning allowance, +extra bytes, alternate ordering or acceptance on another stage/command. Retain +the original stdout/stderr captures unchanged. All existing exact empty-MCP, +nonempty MCP parser channel, ripgrep and149-byte refresh rules remain intact. +No new tuple for the as-yet-unobserved next untrusted MCP command is admitted. + +The existing owned-file hash/mode/alias checks and complete parse_skills / +_require_skills selected-path/enablement policy remain unchanged. In particular +the untrusted A branch must expose only the original user-owned fixture skill, +never A/B project fixture skills, with the prior builtin handling unchanged. +Preserve the authored DO_NOT_TRUST control and all existing caller trust checks. +No profile/env/trust rewrite, new command, API/model/permission/qualification or +source pin change. Observation completion remains distinct from runtime proof. + +## Meaningful inert verification and publication + +Independently state the actual211-byte literal and digest. Replay it through +the actual _probe and complete collect() untrusted A control, retaining18 fixed +commands and all false qualification claims. A full collector fixture must +still distinguish user/A/B and preserve its authored settings, skills and trust. + +Reject the tuple on other labels/commands, nonzero or malformed record values, +wrong stream types, extra/truncated/reordered/CRLF/duplicate/warning/API/auth +bytes. Reject a genuine-looking tuple paired with project/sibling/foreign skill +stdout, missing user skill or an authored-file mutation. Replay the exact held +untrusted stdout/stderr through existing parser/scope checks offline; never +replace its recorded incomplete capture with synthetic success. + +Run the complete Gemini research Python module, AST/diff checks and two +independent code reviews. No Go or vendor/native/positive hosted guard runs +locally. Root alone publishes to existing PR526 on a fresh non-forced ref. +Fresh genuine evidence must complete remaining research stages before any +complete source observation; native/full lifecycle/protocol/cleanup proof is +still separate. No release/new PR or VS Code work. + +## Implemented validation + +Both independent plan and full two-file code reviews approved the finite +allowance. Reviewed collector SHA256 is +dca1042274b97c2fc12a651bc7561a7f6c4cab0041eb246a413afcd5ff58d1b2; +tests SHA256 is +c6e3de8462455145e45ca4d46075b614ddd98832188a6d242bc7d6ec43ef8c17. +The complete Gemini collector module passes28 tests in0.166s (root independent +rerun28 in0.220s), including the full18-call all-false/trust control and exact +literal/hash, hostile bytes/stages/records, scope and authored-mutation cases. + +Offline replay independently checked actual211-byte stderr and1029-byte stdout +against the held research command byte/hash metadata, typed successful record, +original user path from the configured-user command cwd, and existing strict +parse_skills/_require_skills through the actual _probe selection. It returned +the unchanged raw stdout and selected only the original user fixture skill. +The genuine d942 incomplete/all-false record remains unchanged. AST/diff checks +pass; no Go, vendor process, hosted guard or additional command ran locally. +Fresh genuine research must still reach and complete its remaining stages. diff --git a/docs/GROK_PROJECT_BYOK_OBSERVATION_PLAN.md b/docs/GROK_PROJECT_BYOK_OBSERVATION_PLAN.md new file mode 100644 index 000000000..e7f99fa0c --- /dev/null +++ b/docs/GROK_PROJECT_BYOK_OBSERVATION_PLAN.md @@ -0,0 +1,181 @@ +# Grok installed startup through its documented custom provider + +## Current observed boundary and authority + +PR522 current source b4a2d5dea1cc2cd9a0165660924732ec6e1df811 has tree +d09f2103389f697b3c6c5afb3f01056aae247d93. Local baseline +648d79623b71efd1518d60eb02f90ffe7f34b4f3 has that exact tree, preserving +the published runtime concurrency overlay. Genuine runtime40408742120 already +passes public project add and the exact disabled/untrusted installed-candidate +inspection, then the ordinary native startup asks for vendor sign-in. That +failure proves neither loaded skills nor an unavailable custom-provider route. +All five qualification flags and vendor/model flags remain false. + +The publisher's official settings and enterprise documentation, checked on +2026-10-27, documents user-scope model. with model, base_url, env_key and +api_backend=chat_completions, plus per-model key resolution for headless use: +https://docs.x.ai/build/settings/reference +https://docs.x.ai/build/settings +https://docs.x.ai/build/enterprise +These current documents support a bounded custom-provider experiment, not an +assertion that the pinned1.0.70 binary has already accepted it. Its reported +build f50904eaee6c does not resolve in the publisher's public grok-build Git +history, so no immutable source claim is made for that build. + +The actual pinned help permits --model, --single, streaming-json and the +existing deny-all command. Preserve the exact native pin and original HOME. +This slice may configure an explicitly labelled scripted loopback provider; +it may not invent a vendor account, use a real API key, alter enterprise +requirements, grant trust, enable tools or weaken any installed ownership guard. + +## Bounded implementation after two independent plan GOs + +Add one Grok-only helper and inert contracts, with small explicit hooks in the +existing four-client attempt. No new generic provider/client framework. +Before the first native command in this fresh fixture, start a context-owned +HTTP listener on 127.0.0.1:0 and exclusively create original +HOME/.grok/config.toml. Select one fixed model uap-grok-fixture in that user +config, with model=uap-grok-fixture, the held loopback /v1 base URL, +env_key=UAP_GROK_TEST_PROVIDER_KEY, api_backend=chat_completions, +supports_backend_search=false, supports_reasoning_effort=false and max_retries=0. +Use the exact --model uap-grok-fixture on the existing native startup argv. +Keep --deny "", default permission mode, no-subagents, disable-web-search and +max-turns1 unchanged. No trust configuration is authored; the existing native +inspection must still prove the untrusted disabled Prepared candidate. + +Generate a fixture-only private random credential for that loopback endpoint. +Pass only its explicit environment variable in this Grok fixture's closed child +environment; inherit no host credentials. Do not put its value in config, +argv, command receipts or evidence. Add the newly authored config's digest to +the existing protected set before any native command. Never reset that baseline +after startup. Preserve all runtime/archive/source/installer/receipt/data guards. + +The listener accepts only POST /v1/chat/completions with the exact held bearer, +loopback peer, bounded headers and a maximum1MiB body within the original total +deadline. Permit at most one admitted request and one fixed response. Record +wrong-route/auth/method/duplicate/overlimit/invalid-JSON failures as finite +categories only, without echoing headers, credentials or exception text. +Strictly decode JSON with the existing duplicate/depth/number limits. Require +an object, exact selected model, stream=true and a nonempty bounded messages +array. Unknown request fields remain opaque captured research bytes; they are +not approved runtime grammar or accepted qualification. Do not interpret or +execute tool requests. Reply with the minimal fixed OpenAI-compatible SSE text +completion followed by [DONE], containing only a fixture sentinel independent +of installed skill contents. No tool-call response or provider-directed action. + +Capture the admitted request body and fixed response bytes under two exact +Grok-specific filenames plus one bounded provider receipt. Redact the private +fixture credential before any bytes enter f.files, including native stdout and +stderr. The receipt contains only fixed transport/model labels, request and +response counts, whether the exact test credential matched, finite error and +ordinary listener shutdown status. Never retain HTTP headers, config bodies, +real auth state or private native profile inventories. Reject any remaining +fixture credential canary before artifact serialization and in the shared +Python envelope validator. + +Tie HTTP deadlines to the existing fixture context and use bounded server +read/header/write/idle deadlines. Close the listener and active handler on every +exit, including constructor/setup/native failure; await its serve goroutine +and record actual shutdown outcome before the attempt summary is finalized. +Cleanup failure remains a test failure. Do not extend the original150/180-second +attempt budgets, native60-second command limit, command inventory, process +supervision, hosted admission or output bounds. Other three clients receive no +listener, profile, environment, argv, provider artifact or cleanup change. + +This is a first measured custom-provider capture. Preserve the existing +deliberate runtime fatal gate even if the native command exits0. No exact +native session/stream/skill-load grammar is inferred from a scripted text +response. All qualification, vendor-authentication and real-model flags remain +false. A fresh genuine hosted capture must establish whether the pinned native +client accepts this supported route and what it actually discovers before a +separate reviewed full user/A/B lifecycle and native restart/removal slice. +Grok's production project MCP remains explicitly unsupported. + +## Closed scope and verification + +Files: repotests/agentplugins_project_native_cli_attempt_test.go; one new +repotests/agentplugins_grok_project_native_provider_test.go containing the +bounded helper; one new matching provider-contract test file; existing shared +CLI argv contracts only for their exact Grok argv expectation; and +scripts/project_native_runtime.py plus scripts/test_project_native_runtime.py +for the exact Grok-only provider member/receipt/secret closure, and this plan. +Preserve all existing shared-client and failure admission cases. + +Inert actual-HTTP contracts must prove the single exact route/credential/model +exchange and fixed SSE, refusal of wrong route/auth/method/model/stream, +duplicates, malformed or duplicate-key JSON, oversized body and late/cancelled +requests, bounded cleanup after partial input/failure, and secret-canary +redaction/refusal. Verify unchanged deny-all flags, protected config bytes and +original HOME; no loopback authority is added to other clients. Python contracts +must reject incomplete/extra/misrouted provider members, inconsistent counts, +malformed finite receipt fields and unredacted canaries; all existing source, +member, failed-attempt and false-qualification checks remain required. + +After independent code review, use the exclusive Go/lint slot for focused +Grok/new-provider/shared-CLI contracts, affected all-enabled lint and unfiltered +whole-file size/architecture lint. Run the shared Python admission tests, +gofmt/whitespace checks and retained actual failed Grok envelope replay. No +vendor process executes locally. Root alone publishes to existing PR522 with +fresh actual ref and expected_sha, force=false. No new PR or release; VS Code +is deferred by the latest explicit owner instruction. + + +## Review checkpoint + +CLI R1 and desktop R2 independently approved plan SHA256 +dd85798b4871626281b79ca3e4692584a5158633b46ef403be544fe3d804ff56 +before plan commit b9a40b860061b3671fff62cb9f17be2da69ae195 and source edits. +The listener is created only after deferred finish owns cleanup, before the +first native command. The implementation additionally enforces a literal +origin-form RequestURI, held Host, single authorization/content-type values +and actual loopback peer; no unknown request field supplies qualification. + +Both critics independently approved the complete six-file implementation +manifest SHA256 7a33859c0ac4df509f0e18021b5c4a169ee41d58cd30a99ff114da585ddcfd20, +conditional on actual focused Go and both lint gates. All23 existing/new shared +Python admission contracts pass in0.023 seconds. The Go gates are pending the +exclusive shared validation slot; this checkpoint does not claim they passed. +No vendor executable has run locally. The genuine new-source first capture and +all subsequent full native lifecycle proof remain outstanding. + +## Final correction and actual local verification + +An independent critic subsequently found that whole-JSON decoding alone misses +an escaped private-key prefix in a multi-record native JSONL stream. The final +correction retains raw and whole-JSON canaries, then checks each bounded JSON +record before capture and at final admission. Go uses a Go1.22-compatible +`bytes.Cut` loop without an all-lines allocation; Python checks every Grok +member, including envelopes without a provider receipt, through bounded +`BytesIO` iteration. The existing one-MiB native member bound applies first. +Actual first/last-record escaped-prefix controls, benign JSONL and over-bound +controls cover the demonstrated gap. Both independent critics re-reviewed the +correction and approved the final bytes. + +The actual affected lint initially reported three concrete issues: the inert +route request needed an explicit context and `http.NoBody`, and connection-state +accounting needed a tagged switch. These were fixed without suppression or a +newer-than-Go1.22 API; both critics approved the exact mechanical delta. Final +provider source SHA256 is +`1cdd22201b8b18966515b92f1026fd2ee8a732bc393e4cbf900c353f11dc9d8a`, +and its contract file is +`6aeaf8af3953324b28075e042835b4875e3e66e2c780b831c4fb30bc93bba801`. +The shared Python admission source/test hashes are +`21f93c824812be17d06a4e7ce70757e3caf957d50686e4353eb0c26d2adaa568` +and `1d22830536b24de7241ecd40942ab7a5c06696288153fdc1882ff8b1bf406f98`. + +Final focused Grok/provider/shared-CLI inert Go tests passed in `1.026s`. +All23 Python admission contracts passed in `0.031s`. Actual all-enabled affected +lint and unfiltered whole-file size/complexity/architecture lint each reported +`0 issues`; gofmt and diff whitespace checks pass. Checks used the exclusive +slot, canonical Go1.26.10, bounded existing caches and direct source indexing +after the duplicate toolchain cleanup. No vendor executable ran locally. + +The actual prior Grok native envelope from source +`b4a2d5dea1cc2cd9a0165660924732ec6e1df811`, tree +`d09f2103389f697b3c6c5afb3f01056aae247d93`, also re-admitted all19 closed members +under the corrected Python code. Its inner SHA256 is +`dfa0d82412f2654e51bcfcde0c856f00763774dd77c5617b99e284f85704b354`. +The failed-attempt result, all five false qualification flags, false vendor-auth +and false real-model flags remain unchanged. These local checks qualify the +fixture correction only; genuine acceptance of the documented provider settings +and the complete native project lifecycle remain outstanding. diff --git a/docs/GROK_PROJECT_CONFIG_MUTATION_DIAGNOSTIC_PLAN.md b/docs/GROK_PROJECT_CONFIG_MUTATION_DIAGNOSTIC_PLAN.md new file mode 100644 index 000000000..0e5d4f8a0 --- /dev/null +++ b/docs/GROK_PROJECT_CONFIG_MUTATION_DIAGNOSTIC_PLAN.md @@ -0,0 +1,113 @@ +# Grok: bounded original TOML mutation diagnostic + +## Observed boundary and source authority + +Published PR522 source6f001863659da7fc9fae4302ec43c6e6a8c2f840, tree +b272f10383728fff0da86f79566e43aa2a400dc2, has the already audited genuine +run40460245073/native122046695647. The original HOME/.grok/config.toml +digest changes after a rejected provider route and canceled native startup. +The changed bytes and fields are not observed. This does not identify a +credential failure, a harmless default, or a permissible configuration rewrite. +The route observation, nested privacy and complete-JSON numeric corrections +are separately reviewed local work and must remain preserved on this lane. + +Current f.check has only the generic protected-digest fatal for this file. +configureGrokProvider exclusively authors the supported original-user recipe, +records its digest before the first native child, and keeps one held listener. +No equivalent Grok config diagnostic exists. No immutable pin1.0.70 config- +writer implementation has been established; the unresolved build identifier +and current documentation cannot supply the unknown changed setting. + +The workspace already pins pelletier/go-toml/v2 v2.3.0. Use that existing +parser and the existing held ordinary-file read mechanics; add no dependency, +product parser, account, native request or executable acquisition/execution. +This plan is diagnostic only. Root owns Grok code/publication; CLI drafted it. + +## Eligibility, original cancellation and read boundary + +Add one small Grok-only hook at the existing changed protected-file branch, +before the same unchanged fatal. Require the exact original-HOME config path, +Grok client, configured provider, recorded native-attempt use and all three +native-attempt capture members. Capture at most once, including refusals. +Do not inspect other paths/clients or alter either expected/observed digest. + +The route guard cancels the existing fixture context before this post-native +check. Context cancellation alone must not manufacture fresh execution time: +the original f.started+150s work boundary remains authoritative. If that +absolute boundary has expired, record only a fixed work-deadline refusal and +read nothing. If early provider cancellation occurs while that original work +budget remains, permit this one bounded read as part of the already-required +immutability diagnostic. Do not start a child, renew a context/deadline, retry, +change cancellation, or use the180s cleanup reserve for diagnostic work. +The original total180s check, process/cgroup cleanup and fatal remain intact. + +Hold/read at most64KiB with existing no-follow, ordinary original-user-owned, +single-link, stable-inode/metadata/parent checks and checked close behavior. +Require its SHA256 to equal the digest already observed by the fatal guard +before interpreting bytes. No Readlink, redirected HOME/profile or second read. +Keep the actual byte count and hash facts finite; never retain the TOML body. + +## Parse, independent recipe and finite projection + +Hold the exact authored configuration bytes when they are first written; +derive expectations from those bytes and held listener/model identity, never +from the changed file. Parse the held recipe and observed bounded file as +complete TOML with the existing library's duplicate/syntax checks. Export only +fixed refusal categories for parse/read/recipe/value failures, never errors. +Bound decoded structure to depth32,16384 nodes and4096 UTF8 bytes per key. + +This diagnostic supports only tables, arrays, strings, booleans, integers and +finite floats. Unsupported date/time/other values or nonfinite numbers cause a +fixed type/value refusal without hashes or partial metadata. Preserve integer +versus float categories. No TOML-to-product configuration or acceptance parser +is added. Any encoded private fixture credential in decoded keys/values must +refuse before projection or hashing, using the reviewed bounded privacy check. + +Report fixed presence/type/equality facts for exactly eight authored scalar +paths: models.default and the model.uap-grok-fixture fields model, base_url, +env_key, api_backend, supports_backend_search, supports_reasoning_effort and +max_retries. Their labels are static. Do not export any actual string/value; +in particular no API key, endpoint/port or env_key value enters evidence. +Also report presence-aware whole semantic equality and top-level field counts. + +For changed top-level members only, report total changed count and at most +three deterministic summaries sorted by member-name SHA256. Each summary has +only the name SHA, finite before/after type (including absent), and SHA256 of +standard Go encoding/json Marshal bytes for each present validated TOML value. +This declared semantic encoding is not a claim about raw TOML spelling/order. +Do not walk arbitrary leaf paths or serialize unknown keys as dynamic keys. +Before emitting any hash, refuse private canary content; hashes are never data +ownership, native success, trust or baseline authority. Bound every canonical +value to64KiB; overlimit/encoding failure emits no partial value metadata. + +Bound the complete serialized observation to2KiB, including original digest, +status, known facts and differences. Omit additional summaries deterministically +with an exact omitted count, or use a fixed no-detail bound refusal. Preserve +all original protected maps, configuration bytes, expected recipe and fatal +outcome even when semantic equality or every known-field comparison is true. + +## Actual inert controls and publication + +Exercise the real eligible held-file hook with independent TOML fixtures: +format-only rewrite, added/removed/changed table/scalar, each supported type, +integer/float distinctions, exact known recipe and changed safety flags. +Compare selected hashes to independently stated semantic byte strings, not a +copy of the implementation. Include private unknown names/values/paths and +encoded provider canaries; none may enter the complete serialized observation. +Prove strict duplicate/malformed/deep/large/unsupported-time/nonfinite refusal, +zero/many changes and stable selection under reordered keys. Verify full file +identity/bytes and original protected digests remain unchanged before/after. + +Test actual early-canceled context plus still-live original work budget, and +expired original work boundary before any read callback; no new deadline is +created. Cover wrong client/path/missing native triple, once-only behavior, +symlink/hardlink/held-digest mismatch and private read/parse errors. Preserve +the original child-fatal/profile contracts and failed all-false artifact replay. + +Two independent plan GOs precede root-owned source edits. Run focused inert +Grok/shared contracts, affected all-enabled and unchanged whole-file lint in +the exclusive slot; obtain two independent code reviews and exact tree checks. +Root alone publishes on existing PR522 using a fresh non-forced ref lease. +Review fresh genuine route and TOML observations independently before any +later fixture/policy/lifecycle amendment. No native admission or permission +change, local vendor/installer, new PR, release, VS work or qualification claim. diff --git a/docs/GROK_PROJECT_CONFIG_MUTATION_DIAGNOSTIC_VALIDATION.md b/docs/GROK_PROJECT_CONFIG_MUTATION_DIAGNOSTIC_VALIDATION.md new file mode 100644 index 000000000..1cb874dd4 --- /dev/null +++ b/docs/GROK_PROJECT_CONFIG_MUTATION_DIAGNOSTIC_VALIDATION.md @@ -0,0 +1,55 @@ +# Grok original TOML diagnostic: exact reviewed validation + +## Source and review + +The source base is published PR522 head +`84d7ec345e9e7d766aa0cc8fad72b4cbcf0aeadb`, tree +`13dccf898c2efce4b831c46aa3b6eb2a06aa4c71`. The accepted plan remains +`GROK_PROJECT_CONFIG_MUTATION_DIAGNOSTIC_PLAN.md`, SHA256 +`b539cb9ee53b7184ad5e8fcecc9348f97584b46e6787a00a3033204d6989377e`. +Its independent root R1 and shell R2 plan approvals preceded implementation. + +The exact five-file source manifest is +`5447c3a733067d95856c2cb3ff7735d135534c9d3029e1d2c058da1c882b836c`. +The retained shell review gave final CODE GO on that manifest. A fresh +independent CLI reviewer read the complete five-file delta, held-file reader, +privacy/provider integration and frontend admission, independently verified +all five hashes, and gave CODE GO without findings on 2026-10-27. + +The local code commit is `35ce606713a523a69d4a1036eacb827b9434fff9`; +its exact reviewed tree is `76127307c3399c3a9d53f8cb7dffc1f5d864beea`. +This validation record changes no reviewed source bytes. + +## Actual local gates + +The focused inert Go contracts selected by +`^(TestGrok|TestProjectNativeCLI)` passed in 1.158 seconds with Go 1.26.10. +The actual all-enabled affected-line lint gate against the source base +reported zero issues. The unchanged unfiltered whole-repotests +revive/funlen/gocyclo/gocognit/dupl/depguard gate also reported zero issues. +The exact five Go files are gofmt clean and the staged whitespace check passed. + +The first sandboxed compile was unable to write because the shared filesystem +was full; it was an environment failure, not a test result. After removing +only stale compiler outputs and disposable task caches, the same authorized +inert tests and both lint gates completed with approved execution outside the +disk-restricted sandbox. No source, evidence, module cache or toolchain was +removed. No vendor client or positive hosted-environment mock ran locally. + +## Genuine evidence and unchanged boundary + +The current genuine runtime is run `40495826839`, native job `122173276421`. +Its native artifact `12733470239` has verified outer SHA256 +`7801ec66e7813cef0f7856964a3933d44a4f4742feb9b682bcdd3c9a40ace349`. +The actual 20-member native archive replays through current Python admission +with its original failed/incomplete state and all five qualification flags +false. The installed candidate remains disabled and untrusted. The provider +record retains its rejected GET route, zero accepted requests/responses and +ordinary shutdown; no unseen request path or configuration value is inferred. + +The new diagnostic performs only a bounded, once-only observation before the +same fatal protected-file guard. It does not adopt changed bytes, renew the +original work deadline, permit an unknown setting, or qualify a native result. +Fresh source-bound hosted route/TOML evidence and its independent review remain +required before any subsequent fixture or lifecycle amendment. Root alone +owns publication to existing PR522; no release or VS Code work is included. diff --git a/docs/GROK_PROJECT_NATIVE_SHARED_CLIENT_PLAN.md b/docs/GROK_PROJECT_NATIVE_SHARED_CLIENT_PLAN.md new file mode 100644 index 000000000..7f5e46b71 --- /dev/null +++ b/docs/GROK_PROJECT_NATIVE_SHARED_CLIENT_PLAN.md @@ -0,0 +1,124 @@ +# Grok: source-defined shared HTTP client opt-out for the existing capture + +PRE-CODE proposal. Obtain two independent GPT-6.1 high/xhigh reviews before any +source edit. Read AGENTS.md, PROJECT_INSTALL_OWNER_SCOPE.md, +AUTHORING_CAPABILITY_PRESERVATION.md and the completion plan. No release or +VS Code work. Existing production behavior and strict provider admission stay +unchanged. This is one fixture configuration experiment, not native qualification. + +## New exact hosted evidence + +Current published source a1af0da362f020111a3af6a16e50cd265a708224, +tree87fb8a405c0e362fd5dad867e105523029ff7d12. Genuine runtime40579668485, +job122458819911, fails after3.99s. Public add succeeds Prepared. Native inspection +exits0 in79ms and joins the exact binding target/physical ID and project scope; +plugin enabled=false,projectTrusted=false,one provided skill,no loaded skill or +MCP server. The native --single child fails after322ms, with empty raw streams. +The strict provider observes GET and exact literal RequestURI '/', loopback peer, +matching Host, relative URL, empty URL host/raw path and absent Content-Type. +It rejects before credential/body admission, cancels the context, admits0requests/ +0responses and closes normally. The context flag is not a timeout-expiration +measurement. No Authorization value/absence, body content or prewarm identity +was captured; all5/runtime/auth/model flags remain false. + +Native12769367534:4674B,20closed members,outer +2f7a5bfca938ffe30cb60fc4f216b7825b2d41e9c5ccca29b38af009969cae12, +inner1b3ac8f968f012832421bffa9a2255b4a82f34aaa81415e29eb618ee2f3d141d. +Frontend12769462428:3386B,25members,outer +c31367f0eedf32083bed51bd4dba9aaf8ba018c886e2a1f2836fb8589e1ad72a. +Exact clean source/tree/build,24frontend stream joins and unchanged exact-source +failed admission pass root audit /tmp/uap-additional-grok-a1af-current-w3kcpcdl/report-final.json, +SHA2568e9b49eab61de2a98dcfb4ab714e5bbf604c4e765696301df731f1e109ac830d. Independently review these actual raw facts before approving this plan. + +## Primary source guidance and its limit + +Verified official xai-org/grok-build snapshot +2bdd1d6a6369de0e8c68132ea4539e9abd9e14a8 contains the candidate startup chain: +session_setup -> sampler_prewarm -> prewarm_transport. The last function obtains +the origin from configured base_url and issues GET to that origin via a shared +uncredentialed HTTP client. Its official wire test observes GET '/'. This source +mechanism is consistent with the new actual URI, but does not prove the shipped +1.0.70/f50904eaee6c binary uses that exact implementation. That build hash does +not resolve in the public snapshot; keep the uncertainty explicit. + +The exact shared_http.rs blob e659c7fcc4eb8bba52a3c882fa57f670269c4bf4, +SHA25675e919946fb52b887f9bb0a905d8244596b0228235b1eed8313b76d50f8b5943, +defines GROK_SAMPLER_SHARED_CLIENT='0' (or case-insensitive 'false') as a +process-latched rollback to a fresh reqwest client per SamplingClient. Auth, +extra headers,baseURL andUser-Agent remain applied per request; this switch is +not an authentication or permission override. pooled_client returns SharingDisabled +before creating a pooled client, and prewarm_transport returns before its GET. +Exact prewarm.rs blob4ee8ad76886f1d28c8a7e1269623fa27e9f5fb3d, +SHA256626aa25d3515423372a812b785f7ccdc090161a3a83dd7a0f4355401602e34e5. +Official shared_http_kill_switch test blob4db871673b5c07023bc3955840397cc478bf90d2 +pins independent client construction at this snapshot; it is not a test of our +shipping binary. Source research /tmp/uap-additional-grok-first-route-research.json, +SHA256f793a0bafe287387d446ac081459fac350653269819c7a2aecc57df1260f6dd0, +retains seven independently Git-blob-verified primary source receipts. Refer to +those exact publisher URLs, not an assumed current main or a third-party account. + +## Proposed narrow fixture change + +Only in projectNativeCLIAttempt.env's existing Grok + nonnil held fixture-provider +branch, append exactly GROK_SAMPLER_SHARED_CLIENT=0 alongside the existing fixture +key. Keep the base closed environment, original HOME and updater setting intact. +The value is authored by the fixture before each child starts; never import an +ambient value or mutate process-global environment. Applying it to the existing +Grok child sequence is consistent before each separate native process's possible +once-only latch; no new command, process, request or capture stage is added. +A Grok fixture with no held provider, every other client and ordinary production +commands receive no new variable. Do not add a generic configuration API or +client-specific branch elsewhere in the production installer. + +The provider file, literal authenticated POST /v1/chat/completions route, Host, +loopback, MIME, credential, body/model, count, response, cancellation and cleanup +gates must remain byte-identical to a1af. GET '/' remains rejected. Keep original +config bytes, model selection, permissions/default deny-all, untrusted project, +no-subagents/no-websearch/max1turn flags,150second work/180second total origins, +60second native command and all acquisition/scanner/source pins unchanged. Do not +modify a provider to serve the prewarm, admit empty credentials or normalize URIs. +The failure artifact schema, shared CLI matrix and all qualification values stay +unchanged. Existing finite route diagnostics continue to describe actual failures. + +This is a source-guided control applied to the actual pinned client: a new genuine +run must determine whether it honors the opt-out and what request follows. If it +still sends GET, or rejects the setting, preserve that result and do not assume +the binary matches the publisher source. If it reaches authenticated POST and +native output, independently review those actual bytes before planning a grammar +or full lifecycle. A native response alone cannot load an untrusted disabled skill. + +## Meaningful inert verification + +Use the existing environment/protected-source fixture helpers, no native binary. +Check the concrete constructed child environment, with ambient conflicting/private +values: exact single0variable only for Grok with held provider; no ambient escape; +all original HOME/profile/fixturekey/updater values retained. Check Grok without +provider and Qoder/Kiro/Windsurf fixtures omit it, even if an irrelevant provider +pointer is supplied. Preserve existing environment/parser/provider contracts. +Do not test the Rust publisher code locally or manufacture native eligibility. + +Run focused Grok/shared Go contracts, current Python runtime admission contracts, +unchanged old a1af raw failed replay, actual affected all-enabled and unfiltered +six-linter gates, gofmt andwhitespace. Provider digest must remain +865265e28731ceee3816ab1d5c4fc137d29d859e6851675d90fbcc867f1daa88. +Verify new Go assertions do not simply compare an echoed constant: they must +cover routing by client/provider, ambient isolation, absence of duplicate variables +and retention of existing original-profile/credential values. A real inert child +is unnecessary unless existing composition fails to expose the concrete env. + +## Review and publication + +After two exact plan GOs, commit this accepted plan before the small code change +in an isolated branch from fresh agreed a1af. Two independent exact code reviews +and executed serial gates follow; root coordinates the shared validation slot. +Preserve other continuation checkouts and all existing history. Root publishes +normal expected-head fast-forward to existing PR522, then reviews the actual new +hosted result. No force, replaced PR, unchanged retry, runtime/lifecycle/auth/model +success inference, main merge, release or VS Code authorization is included. + +## Accepted before implementation + +Both independent GPT-6.1 Sol xhigh reviewers accepted the exact draft SHA256 `bd14b445e2c257e231ac9d8e609fd0326b4b6f5b877298c5a91b6e19a8e78d47`. + +- `/tmp/uap-additional-grok-shared-client-plan-R1.md`: SHA256 `98c374d5d2aff23e7af63b95feb934218e474ec4f49cf852cee13644378cf36c`. +- `/tmp/uap-grok-shared-client-plan-r2-review.json`: SHA256 `ff22fd6d0d97768937f877f611d09726c620f7f0ecd0d2d8adb039b47eb11940`. diff --git a/docs/GROK_PROJECT_NATIVE_SHARED_CLIENT_VALIDATION.md b/docs/GROK_PROJECT_NATIVE_SHARED_CLIENT_VALIDATION.md new file mode 100644 index 000000000..5057be68c --- /dev/null +++ b/docs/GROK_PROJECT_NATIVE_SHARED_CLIENT_VALIDATION.md @@ -0,0 +1,232 @@ +# Grok shared HTTP client fixture: reviewed validation + +Reviewed code: `74f72491fdbeb722e845de71217e9d1751330020`. +Tree: `53b0e7f46404658bd385b92edddea12522c247dc`. +Base: `a1af0da362f020111a3af6a16e50cd265a708224`. +Approved plan commit: `7e5e5629d3f730df7bb2ee17bf2765882cd74112`. + +Two independent GPT-6.1 Sol xhigh reviewers approved the exact plan before code +and the final implementation after inspecting executor receipts. No blocking +source findings remain. + +The existing Grok child environment receives `GROK_SAMPLER_SHARED_CLIENT=0` +only when its fixture holds the private provider. Eight concrete client/provider +cases verify routing, ambient isolation, no duplicate entries, retained original +HOME/profile/state/Git/key/updater values and no process-global mutation. + +The provider source stays byte-identical, SHA256 +`865265e28731ceee3816ab1d5c4fc137d29d859e6851675d90fbcc867f1daa88`. +Its exact authenticated POST route, request grammar, response, failure latch, +cancellation and shutdown remain unchanged. GET `/` remains rejected. No client +pin, config, trust/permission, command, timeout or qualification flag changed. + +## Actual local inert gates + +- Focused Grok/shared CLI Go contracts: PASS, package1.138 seconds. +- Python runtime admission: 38 tests PASS,5.503 seconds. +- Affected all-enabled lint: zero issues. +- Unfiltered revive/funlen/gocyclo/gocognit/dupl/depguard: zero issues. +- Original a1af native archive: all20 member bodies and the summary admitted + unchanged; failed status and allfive/runtime/auth/model false flags preserved. +- gofmt, whitespace, source-manifest and unchanged-provider checks passed. + +Only inert repository contracts and artifact admission ran locally; no vendor +binary or scanner ran. The public source supports this configuration experiment, +while equivalence to the shipping1.0.70/f50904eaee6c build remains unproved. +A new genuine disposable hosted capture must show whether the pinned binary +honors the setting and what request follows. The previous failure is not promoted +to success. This validation makes no lifecycle, authentication, model, main-merge, +release or deferred VS Code claim. + +## Exact review and execution records + +- `/tmp/uap-additional-grok-shared-client-code-R1.md`: SHA256 `15f043736ab0deadf9b985eafbb8fd7bf148e3853cb81d5631b249a06a5157cc`. +- `/tmp/uap-grok-shared-client-code-r2-review.json`: SHA256 `8e842b6b91bc559f53f47893d14ee0b7427d42b2955ef868876d46b6897ef842`. +- `/tmp/uap-additional-final-serial-gates-1d4m_qyl/report.json`: SHA256 `1ca286a35b6c73e4dc32b6ef5525741aa8b323bb726ceda86968c06c017e00de`. +- `/tmp/uap-additional-final-serial-gates-1d4m_qyl/grok-unchanged-old-replay.json`: SHA256 `82ccf6beb6b90bd35bfac3a0ef2eb983f62286a82bc99ce86c0909503b823479`. + +Local receipt paths identify this execution. The committed source, approved plan +and this validation document preserve the reviewable repository history. + +## Refused second main request: bounded diagnostic candidate + +The separate accepted amendment is committed before code at +`bb94f00bba12d59b80bdd2bfd600aa3af6e66d72`, following two independent plan GOs. +It addresses the actual `348e2ce8` capture: one first main exchange and one title +exchange completed, then an additional main HTTP attempt hit the original +duplicate refusal before its body was read. That capture remains failed and +all five qualification flags, runtime, authentication and real-model claims +remain false. Its second body and purpose are unknown. + +The candidate adds one main-only observation slot. Original context, literal +route, loopback and authentication checks run first. Under the existing mutex, +the completed first main request/response and distinct held title fixture permit +one atomic duplicate/failure reservation. Body reading and privacy validation +run outside the lock, at most 1 MiB + 1, under the unchanged five-second HTTP +read limit and original 60/150/180-second origins. No deadline is renewed. +The unconditional deferred path settles the observation and executes the +original HTTP 400 refusal and duplicate cancellation. A third or concurrent +request remains immediately refused and can cancel a blocked observer; it +cannot claim another slot, replace the first failure or increment counters. + +Only a complete bounded UTF8 strict JSON object that passes both held-key and +recursive privacy checks is retained, opaquely. No field becomes a new model, +tool, prompt or response grammar. Every refusal retains zero raw bytes. After +the original stop settles handler/connection bookkeeping, export snapshots +state under the lock, then validates and persists outside it through the +unchanged evidence/privacy guards. + +The optional fixed `grok-provider.duplicate.json` receipt is at most 2048 bytes. +Its closed fields are schema version 1, role `main-duplicate-diagnostic`, attempt +index 2, a finite status, original failure `duplicate`, false response-issued, +captured byte count and SHA256. `grok-provider.duplicate-request.json` exists only +for a captured status, within the existing 1 MiB member bound and with its exact +length/hash. Refused statuses have no raw member, zero length and empty digest. +Go and Python readers join the pair to the failed all-false tuple, original +first exchange and separate title evidence, and independently recheck structure, +privacy, member isolation and byte/hash consistency. Historical captures without +this optional pair retain their original admission. + +New inert contracts are authored for the actual loopback first/second/third HTTP +sequence, original five-second partial read, concurrent cancellation and stop, +ineligible/title/incomplete-first requests, finite JSON and both held-key privacy +refusals, plus coherent hash-updated artifact mutations. These contracts are +synthetic and have not yet been executed for this candidate. The existing +main/title schemas and response bytes, command/config/profile/process guards, +native pins, selection and workflow are unchanged. Before publication this +candidate still requires exact-source executed Go/Python/lint gates, original +capture replay and two independent CODE critics. A fresh genuine hosted capture +and independent raw audit are required to observe any new refused body; even a +safe captured body remains failed, unqualified diagnostic evidence. + +The first code review found a Unicode-scalar mismatch: Go's existing JSON +decoder replaces escaped lone UTF16 surrogates, while Python refuses their UTF8 +encoding. The new diagnostic now refuses unpaired high/low escapes and invalid +pairs, including complete nested JSON values/lines in strings or keys, under +the existing 4x text, 16384 node and 64 depth privacy envelope. Old decoders and +privacy scanners remain unchanged. Valid pairs, literal U+FFFD, raw UTF8, +escaped slash/quotes and ordinary literal backslash-u text remain data. Retained +raw bytes are never normalized. Coherent refusal and raw-preserving positive +controls are authored in both languages; exact-source execution and fresh +independent CODE review remain required. + + +## Final refused-duplicate source checks, 2026-10-28 + +Exact code `221f4a60b8d179f5e8b2ac007fa57ce010957b3b`, tree +`0a1839161a76dd50acf03301d081d0d3bd793a36`, received independent root +and Gemini CODE GOs after the Unicode correction and a one-file equivalent +contract-style correction. All diagnostic helpers, Python and original guards +are unchanged by that final style-only commit. + +The actual focused Go selection completed 56 top-level entries: 233 passed +cases and the unchanged child-only fatal-helper skip outside its child +environment. Its actual parent fatal-guard controls passed. All seven new +duplicate contract groups, including actual partial-body and concurrent HTTP +cleanup, passed. The 46 runtime and 12 Grok Python tests passed on the identical +Python scripts tree. Affected all-enabled lint and unfiltered whole six-linter +gates each reported zero issues. The first style-lint failure is retained. + +Complete original and current Python modules replayed the original 348 +25-member and 611 21-member archives under their exact original source trees; +all bytes and failed/all-false results remain unchanged. The inherited 348 +Cline capture remains independently audited. No vendor client, public installer +or scanner ran locally. This publication only adds validation documentation to +the exact reviewed code. A fresh hosted capture and two independent raw reviews +remain required to observe the refused second body. No second response or +runtime, lifecycle, MCP, authentication or model qualification is introduced. + +## Supported turn-summary suppression before original config freeze + +The fresh diagnostic run `40610932429` on source +`b40da640c388d807cc3dc1fbb36c38e0d1b411ef`, tree +`71b98e819bdd555154096c9c75850b9b40d3f54c`, retained the refused second +main-route request: 1,424 bytes, SHA256 +`303ad4817a23b68aa02717ecedb70404362cf1397324da5a4d25d12f60a86bb5`. +Two independent raw audits admitted only failed, all-false diagnostic evidence. +The system message and wrapper around the actual prompt and fixed reply exactly +match the pinned public source's per-turn dashboard-summary helper. This is a +specific measured side call; it supplies no plugin activation or runtime proof. + +The accepted plan SHA256 is +`3bc56715f4b326634f99210fc7bde69a711c2edbe7c2880fece74ec950c4593e`, +committed before implementation as +`15a2ca3b8b0396a917121d94b4e991737f4a0aec`, tree +`7962f86b94c8749ce57b5bb4776bad6596b2a207`. Root and an independent reviewer +accepted its narrow supported-setting candidate before code. + +The complete two-model TOML recipe now appends the native boolean +`[features] turn_summary = false` before the existing original HOME config's +sole write, authored-byte clone and protected digest freeze. The original HOME, +both model routes and credentials, source/config/permission/process guards and +all deadlines remain unchanged. No environment override, request allowance, +additional response, retry, profile adoption or qualification flag is added. +The independent complete-map contract adds only the expected boolean subtree; +new inert controls exercise the complete frozen recipe, changed/invalid feature +data without authority adoption, and ambient feature/model isolation. +The existing config diagnostic compares its original single-model recipe; +the two-model title recipe therefore retains its finite `recipe-mismatch` +refusal after a config mutation. No semantic diagnostic allowance is added. + +Public source tree `2bdd1d6a6369de0e8c68132ea4539e9abd9e14a8` defines the +boolean feature, config precedence, actor spawn-time snapshot and early return +before dashboard-summary work. Unset later title refresh defaults to this same +feature, so the recipe also disables that later display-only refresh. The +separate initial-title model, request validator, fixed response and counter are +preserved. The public tree is not proven equivalent to the shipping +1.0.70/f50904eaee6c binary; the fresh genuine run must establish effectiveness. + +All main/title handlers, refused-duplicate capture and privacy/export controls, +readers, collectors, workflow, pins, production and other client source remain +preserved. Any unexpected additional request still receives the same refusal +and original cancellation. Even a clean native exit reaches the unchanged +intentional failed raw-review barrier with runtime and every qualification flag +false. Exact code reviews and measured gates are pending for this amendment; +publication and a fresh hosted observation require those checks, followed by +two independent raw audits. This record conveys no new native qualification. + +The author's bounded development selection ran the new configuration controls +and existing complete-map test: four top-level tests and ten cases passed, +with no skips (package JSON elapsed0.019seconds). The raw JSON log SHA256 is +`a3267a561a123b587f25dc8ae3015f2a883edd779c4293ab675f06e3046da66a`. +An initial new-test expectation incorrectly required semantic projection after +the unchanged single-model recipe guard; that failure is retained. Corrected +controls require its exact finite refusal, separately verify TOML/map changes, +and prove that observed bytes and protected authority are not adopted. These +are owned inert loopback/configuration checks, without a native client, public +installer or scanner. Final committed-source gates remain pending. + +## Exact suppression candidate final gates + +Implementation `a922e32f2004e81cfba2f55bf21219a2fbbe3ffe`, tree +`4cb264cd986280dd70eb3701ab4914ddafc04ca3`, received root CODE R1 GO +(receipt SHA256 `c8a911ba3838b4da5146d903ec4c13bbc0eea2ee15219982c20a7628b52577d0`) +and independent Native CODE R2 GO +(`91a82de3d74bf584f9f73b93a2def5e50fc2a817975a75243406998f04aaa8a5`). +Both reviewed all four frozen files, eighteen unchanged whole-file anchors +and the exact two literal exceptions before publication. + +The actual final focused Go selection ran59 top-level tests and243 case events: +242 passed, with only the unchanged child-only protected-fatal helper skipped +outside its child environment. Its actual format-only and migration-flag parent +fatal/guard controls passed; no new feature check was skipped. The package +completed in7.278s. Affected all-enabled lint and whole unfiltered six-linter +checks both exited0 with zero issues. Initial absent-Go-PATH setup failure and +its controlled pinned-PATH retry remain recorded; no source changed. + +Whole original/current b40 and348 raw replays preserved every closed member, +full returned result, original source identity and failed/all-false tuple. +The previous58 passing Python tests transfer through byte identity of the +entire scripts tree `91ae9d8eb2b8f0790fed890da556b6e66597a0cc`; they are not +represented as new executions. Final gate/review receipt SHA256: +`6982f66f2774fb0ec9f0217980c5b2df4453aad84e84a081e379cd7b7f966cdd`. +Whole-reader replay and Python transfer receipt SHA256: +`eea7a4d3a5e9f75e007d72699853e93f74abff604d831dea8a0e8aec8520f54d`. + +This publication adds only this validation record after the reviewed code. +A fresh genuine hosted capture must determine whether the pinned shipping +binary honors the supported setting. Two independent raw audits remain +required. Original initial-title/main/duplicate handling, source/config/pin +and ordinary cleanup guards, time budgets and the intentional all-false +review barrier are unchanged. No runtime, lifecycle, MCP, vendor-authentication +or real-model qualification follows from these inert gates. diff --git a/docs/GROK_PROJECT_OBSERVATION_RECOVERY_PLAN.md b/docs/GROK_PROJECT_OBSERVATION_RECOVERY_PLAN.md new file mode 100644 index 000000000..18f457bf6 --- /dev/null +++ b/docs/GROK_PROJECT_OBSERVATION_RECOVERY_PLAN.md @@ -0,0 +1,111 @@ +# Grok: recover reviewed observation and privacy work after scratch replacement + +## Source and retained authority + +PR522 remains published at `6f001863659da7fc9fae4302ec43c6e6a8c2f840`, +tree `b272f10383728fff0da86f79566e43aa2a400dc2`. The isolated recovery checkout +reproduces that complete tree. Preserve all published behavior and history. +The genuine run40460245073/native122046695647 failed the original provider +route and original-HOME config digest guards. No request body was admitted; +the route attributes and changed TOML members remain unknown. + +The execution environment replacement lost root's unpublished route, nested-JSON +privacy and complete-numeric-JSON correction files. Their old reviews are design +background, not exact-source approval for reconstructed bytes. Shell recovered +the final numeric-only four-file patch; desktop can recover part of the earlier +Python implementation. No lost whole-file hash or old test result is claimed +for a reconstruction. This plan requires two fresh independent plan GOs before +source reconstruction and two fresh full code reviews afterward. + +## Finite route observation + +Keep `grokProjectProviderRoute` byte-identical. When the first winning failure +is `route`, record one optional `route_observation` under the existing provider +mutex, in the same receipt. A preceding failure prevents later replacement. +Other failure paths and cancellation, request/body handling, counts and deadlines +remain unchanged. No raw request, credential, header, hostname or arbitrary URI +is added to evidence. + +The closed fields are method (`POST`, `GET`, `other`), literal request URI +(`/v1/chat/completions`, `/chat/completions`, `/v1/models`, `/models`, +`/v1/responses`, `/responses`, or `other`), and booleans for loopback peer, +matching expected host, relative URL, empty URL host, empty raw path and the +existing exact content-type predicate. Content-type count is `none`, `one`, or +`multiple`; its classification is `missing`, `json-bare`, `json-utf8`, or `other`. +Only one value of at most128 bytes is MIME-parsed for classification. JSON with +no parameters is `json-bare`; exactly a case-insensitive UTF-8 charset is +`json-utf8`. This classification never changes route admission. Multiple values +are `other`, no values are `missing`. Literal exactness still requires one +value equal to `application/json`. + +Python admits the optional exact field/type/enum set only on a started provider +whose first failure is `route`. It rejects inconsistent count/classification/ +exactness and an observation in which every original route predicate passes. +Old receipts without an observation remain admitted unchanged and unqualified. +Use one small new Go route helper/contracts file and narrow receipt/failure +callsites, keeping the original existing provider source below its size gate. + +## Bounded nested privacy and complete-number correction + +Replace the published one-layer JSON scan with the already reviewed finite +design: valid UTF-8, existing1MiB member limit, literal private prefix check, +and one shared budget of four times whole-member bytes,16384 visited nodes and +depth64 across nested strings, keys, arrays, objects, siblings and JSONL lines. +Use the existing strict JSON decoder, retaining its depth32/key4096 and +duplicate/nonfinite/resource refusal. Every extra parse consumes that same +byte budget. Exact-key redaction still happens before final refusal and before +evidence storage/base64 encoding. Do not decode URLs, base64 or arbitrary +substrings and do not change another client's privacy implementation. + +Only a static nonfinite-number error can invoke the extra complete-syntax +decision. Go performs two `json.RawMessage` decodes and requires exact EOF; +Python uses numeric placeholders only for this syntax decision and excludes +nonstandard NaN/Infinity constants. Complete overflowing JSON still refuses. +An ordinary numeric-looking prefix with trailing text continues literal and +subsequent JSONL checks. Integer conversion/resource failures remain conservative. +No node/depth reset, hash exception or new work budget is introduced. + +Implement the Grok-only Go walker in one new bounded helper/contracts file, +remove only the superseded two private helper bodies, and replace the matching +Python function. The current reviewed Cline implementation and retained Grok +numeric patch are references; all reconstructed Grok bytes receive fresh reviews. + +## Separate already approved TOML observation + +Preserve the exact recovered `GROK_PROJECT_CONFIG_MUTATION_DIAGNOSTIC_PLAN.md` +body (original SHA256b539cb9ee53b7184ad5e8fcecc9348f97584b46e6787a00a3033204d6989377e). +Root and shell supplied its two independent plan GOs. It remains a separate +incremental diagnostic slice after these prerequisites, using the original +absolute150-second work deadline even after an early provider cancellation. +Its bounded held read, eight authored scalar comparisons, private-value refusal, +semantic hashes and unchanged fatal are not permission to adopt any rewrite. + +## Required controls and publication + +Route controls exercise the real inert loopback provider, each fixed category, +raw private canaries and unknown values, first-failure retention, absent optional +field on all other reasons, no request/body/count promotion and unchanged stop. +Python hostile enum/type/extra-field/contradiction controls match those fields. +Privacy controls cover nested encoded strings and keys, multiple layers, +JSONL with non-JSON and numeric-looking first lines, `1e999 1e999`, complete +nonfinite values, duplicate keys, invalid UTF-8, oversized keys, aggregate node/ +byte/depth exhaustion and nonmutation. Test the real capture refusal boundary; +do not merely compare one helper to another copy of itself. + +After independent code review, run focused Grok/shared inert contracts, all +runtime Python contracts, all-enabled affected-line lint and the unchanged +unfiltered whole-file six-linter gate in the exclusive slot. Reacquire the +genuine6f archives with API hashes, closed canonical ZIP/CRC/source/stream +checks and replay failed all-false admission. No vendor executable or positive +hosted eligibility may run locally. Source pins, original HOME, authority, +process cleanup, all five qualifications and the deliberate capture failure +remain unchanged. Root alone publishes small reviewed commits to the existing +PR with a fresh non-forced head lease. No release, replacement PR or VS Code work. + +## Reconstructed source validation, 2026-10-27 + +CLI R1 and shell R2 independently approved plan SHA256602585766fd034764fc12a226d50b72570908904f83f34faa23ef2c0d84c5798 before source edits. Both then reviewed the complete reconstructed five-file slice and gave code GOs on the final exact hashes. The existing route predicate is byte-identical. A concrete noctx lint finding was fixed with the Go1.22-compatible checked `http.NewRequestWithContext` test helper; both critics reviewed that final helper and its callsites. + +Focused Grok/shared inert Go contracts passed in1.067s, including an actual test-binary child that verifies nested credential refusal before any capture persistence. The runtime Python suite passed28 tests in0.088s. All-enabled affected-line lint and the unfiltered six-linter whole-file gate each reported0 issues. No vendor client or positive hosted guard ran locally. + +The genuine6f native/frontend archives were reacquired with their original API sizes/SHA256 and inner hashes. Canonical unique ordinary members, bounded sizes and CRCs were checked. Exact source6f/treeb272, empty source/build-clean streams, all24 frontend stream length/hash joins and all20 native bodies passed reconstruction replay. The original route failure, zero requests/responses, unmatched credential and normal provider shutdown remain unchanged. Admission is still failed/incomplete, with all five qualification, vendor-authentication and real-model flags false. This validates the recovered scanner and envelope; it does not qualify native execution or identify the unseen route/TOML changes. diff --git a/docs/KIMI_PROJECT_NATIVE_APPROVAL_POLL_VALIDATION.md b/docs/KIMI_PROJECT_NATIVE_APPROVAL_POLL_VALIDATION.md new file mode 100644 index 000000000..9292f62be --- /dev/null +++ b/docs/KIMI_PROJECT_NATIVE_APPROVAL_POLL_VALIDATION.md @@ -0,0 +1,42 @@ +# Kimi approval poll refusal diagnostic: validation + +Code reviewed: `8311c8e9f571e9fa272abc2daed1a2f367ad160e`. +Tree: `86e78b33b391186b85641fd1838e5e608c85c20b`. +Base: `b2bb2b7f85b5461420f932478b197905e6fc5ad9`. + +The approved plan was committed before code as +`f4aa9ad63dd6726d936b808d59dba0ea39cbe31a`. Two independent GPT-6.1 +Sol xhigh pre-code reviews accepted the same plan; two independent exact-code +reviews then accepted the implementation without blocking findings. + +## Actual validation + +- Inert Python Kimi suite: 57 tests passed in5.650 seconds. +- Inert runtime admission suite: 27 tests passed in6.417 seconds. +- Original b2bb single-tool artifact: all23 raw member bodies admitted unchanged; + its failed result and allfalse qualification claims remained unchanged. +- AST parsing, source hashes and git whitespace checks passed. + +The tests exercise the actual polling observer and its ordinary supervisor around +an existing harmless Python child. They check both refusal causes, the unchanged +20poll boundary, no approval/history/snapshot/shutdown action after refusal, +quarantine, cleanup facts, finite scalar projection, privacy, hostile types, +malformed ambiguity, copied facts, mixed first causes and later cleanup errors. +This gate did not run a native vendor binary, installer or Go process. + +The optional diagnostic does not turn the existing failure into success. It adds +only a bounded reason for the two original multiple-pending guards and the +original exhaustion guard. Existing manual approval validation, timings, +quarantine, supervision and qualification conditions remain unchanged. + +## Exact review and executor records + +- `/tmp/uap-additional-kimi-poll-refusal-code-R1.md`: SHA256 `51ee412c539cdb59e0087ca3a2b6fe0759c94b59364cbb9ef1704131e4ca51d3`. +- `/tmp/uap-kimi-poll-refusal-code-r2-review.json`: SHA256 `b07cca2fcb15eaeb7ee8d2339ce878384542a8c7f0a3096d7d96f12b9e3ce992`. +- `/tmp/uap-additional-kimi-poll-validation-442uupq9/report.json`: SHA256 `33f5eedbbe75926aee8c5b6aeb9dd7b026dab29f0a4298021a33de4dd0cc3ad6`. + +Local record paths identify this execution's review receipts; the committed +source and this validation description remain the durable repository record. +Native follow-through still requires a genuine disposable hosted run after +publication of the composed Kimi fixes. This validation makes no authentication, +model, complete lifecycle, release or main-merge claim. diff --git a/docs/KIMI_PROJECT_NATIVE_APPROVAL_REFUSAL_FACTS_PLAN.md b/docs/KIMI_PROJECT_NATIVE_APPROVAL_REFUSAL_FACTS_PLAN.md new file mode 100644 index 000000000..bb97d1af6 --- /dev/null +++ b/docs/KIMI_PROJECT_NATIVE_APPROVAL_REFUSAL_FACTS_PLAN.md @@ -0,0 +1,123 @@ +# Kimi: finite facts at the current approval refusal + +## Current evidence and exact limitation + +Use PR524 source `03d7c243129c98ecdc4cbb99bfe1a47536a556bf`, tree +`de7a5565545f67e26e7e3e101b843f728e3876b1`. Genuine runtime40553154543, +single-tool job122367952876, still refuses at approvals/validate/validation, +before a permitted MCP call. It does not reach the deliberate history-review +gate. Native12756894604 outer SHA256 +`80fdf584518a9f2d879c61ce0eb12eb8b4b6adcbaa1fc1028c188399406422ac` +contains23 closed ordinary members; frontend12758701279 outer +`443be84f49ffa69c4e789d0cd33b7bd27c71d45ae3f6571af887486c69c3cf80` +contains25. API hashes, bounds and CRCs are verified. The finite diagnostic +records observer/service entry, group_reaped and port_closed, SIGTERM without +shutdown acknowledgement, and no forced kill. Raw approval values remain +quarantined, so no particular remaining field mismatch is claimed observed. + +The earlier unused two-topic diagnostic draft was based on91a and positive +turn acceptance. This new plan is approval-only, on the current exact-turn0 +validator. It does not change that acceptance rule or installed-skills code. +Pinned MCP tool source ba7412305673619ab2010e98e3bc622902f96c1f +defines no execution description/display override; this supports the existing +fallback expectation, but still does not reveal the actual refused response. + +## Finite failure-only observation + +Keep the complete current approval predicate order and return behavior in a +private strict function. A thin existing-callsite wrapper catches only its +existing ValueError refusal, optionally attaches a closed finite observation, +then rethrows a private typed ValueError. ResponseSchemaRefusal passes through +unchanged, with exact class identity and its existing graceful capture path. +All other exception classes retain their existing boundary. Success returns +exactly as before and produces no observation. + +Use one private bounded helper module only if needed for size/architecture, +the existing kimi_attempt.py, existing kimi.py failure diagnostic and their +inert contracts. The existing diagnostic observer copies only prevalidated +facts when it catches the original callback refusal, before the supervisor +can replace that error. It rethrows the same refusal. Final emission validates +the optional facts again under the existing complete2KiB diagnostic-line cap. +Malformed/projection failures suppress optional facts while preserving the +original failure, zero stdout and private-stream quarantine. + +No HTTP call, response parse, profile/event read, retry, prompt, decision, +approval, tool action or continuation is added. Use only the already decoded +single candidate and held session/provider/tool/argument expectations. +No raw request/response, dynamic field name, native path, action/display/args, +timestamp, identifier, actual turn number, hash, exception text or Python +class name may enter evidence. No value becomes permission or authority. + +The optional topic is exactly single-approval, status captured or +projection-refused. Its closed schema contains row JSON type, exact-key-set +boolean, and presence/type facts for the nine fixed required fields plus +turn_id. Type labels are exactly absent/null/boolean/integer/number/string/ +array/object/other. Add only fixed equality booleans for held session, main +agent, provider call, tool, action and complete expected display; approval-ID +pattern and created/expiry timestamp-validity booleans; turn category +negative/zero/positive/noninteger; and display object/key-set booleans. +Never export values or traverse arbitrary display leaf paths into output. +An absent candidate retains the existing generic stage failure only. + +Projection must first reject malformed/excessive input and nonbuiltin JSON +types, use exact builtin type checks and bounded comparisons, and never call +arbitrary rendering/equality on inert hostile objects. All output keys and +enum values are static. Bound decoded inspection to the already enforced +response limits and at most32 depth/16384 nodes; no budget renewal. A refused +projection emits only its fixed topic/status, with no partial field metadata. + +## Controls and unchanged native gates + +Exercise the actual wrapper with a valid current turn0 row: identical tuple, +no diagnostic and only the existing exact one-call decision. Independently +mutate each identity, field/key/type, display, turn category, ID pattern and +timestamp: every old negative remains refused, with only expected finite facts. +Retain later-turn, wrong-tool/session/agent/call/args/action/display, duplicate/ +unknown-schema and ResponseSchemaRefusal controls. Unknown schema must never +be caught as a generic identity refusal or change its graceful branch. + +Plant credential/path/control/identifier canaries and hostile objects in all +candidate fields. Verify complete serialized stdout/stderr contains none. +Test projection exceptions, wrong topic/key/type, oversize and repeated +failures, unknown facts suppression, and the real inert callback/supervisor +replacement seam. Cleanup facts still come only from the actual held command +record. The first refusal stays the last native/HTTP action. + +Obtain two independent plan reviews, then two exact-code reviews and run +the complete Kimi collector/single-tool/supervisor Python suite, AST and diff +checks. No Go or vendor execution is required for this diagnostic slice. +Preserve host/profile/ownership/pin/provider/permission/deadline/archive gates, +the original900s suite and every qualification/auth/model flag. Keep this code +commit separate from the repeated-add Go correction. Root alone publishes +on the current exact PR524 head. Only the next genuine finite diagnostic can +identify the remaining field; any later acceptance change needs its own +evidence-backed plan, reviews and fresh native proof. No release or VS work. + +## Accepted implementation and inert checks + +Root R1, desktop R2 and a separate native CLI review approved proposal SHA256 +`e841ca2be7330be91b787f2a4a015c6a0a329b529cf16a55404921d40c7bbcf1` +before implementation. The strict approval function's AST is identical to the +published function except for its private name; predicate order and return are +unchanged. The wrapper preserves ResponseSchemaRefusal's exact object/class +before the ValueError branch and leaves other exception classes untouched. +A private facts module first bounds exact builtin JSON and then emits only +fixed keys, booleans and categories. The observer holds a validated copy before +the actual supervisor replaces the callback error, and final emission checks +the closed schema and original complete two-KiB cap again. Installed direct +script startup remains independent of this single-tool-only optional import. + +Inert controls exercise the real callback/supervisor replacement with wrong +tool, combined unknown-schema/wrong-tool and later-turn failures, preserving +quarantine, actual cleanup and the last approvals request. Separate controls +cover exact successful return without projection, schema exception identity, +each refused field/type, unknown-schema precedence, bounded hostile objects, +private canaries, malformed facts, projection exceptions and held-copy drift. +The final full Kimi collector/single-tool/shared-supervisor suite passed 65 +tests in 17.727s, after all six new focused cases passed in 0.611s. Python AST +and diff checks are clean. Root and the native CLI reviewer independently +gave exact-code GOs on tree `bcee7cdf3c5b509676118b6346ee40f7999617e4`; +this final validation note changes no executable bytes. These local children +are inert Python processes; no Kimi, vendor binary, public installer or hosted +environment surrogate ran locally. The current genuine 03d7c243 approval +failure remains unqualified; only a new hosted run can supply its finite facts. diff --git a/docs/KIMI_PROJECT_NATIVE_CACHE_KEY_PLAN.md b/docs/KIMI_PROJECT_NATIVE_CACHE_KEY_PLAN.md new file mode 100644 index 000000000..b2fc8d4d7 --- /dev/null +++ b/docs/KIMI_PROJECT_NATIVE_CACHE_KEY_PLAN.md @@ -0,0 +1,50 @@ +# Kimi single-tool provider: observed session cache metadata + +Status: PRE-CODE draft; no provider implementation changes authorized until two independent GOs on this exact plan. Base source is PR524 b2bb2b7f85b5461420f932478b197905e6fc5ad9; implementation will be composed on the reviewed disjoint polling-diagnostic branch (code8311c8e9f571e9fa272abc2daed1a2f367ad160e) and then the independently reviewed scoped-selection fix. Provider source is byte-identical on these bases. + +## Concrete observed failure + +Genuine disposable GitHub-hosted run40569825577, job122438517585, source b2bb2b7f85b5461420f932478b197905e6fc5ad9/tree b12354b2565a05d14037556f8493b149d7d36ea2 produced native artifact12768461663 (23 members). Its original provider-request-1.json has SHA256 ddd8a402037716fe582f854dcf5d5dae1ebb902dc6b3a962466e4d34874c4de7. It offers exactly the installed fixture tool/model and includes prompt_cache_key, a44-byte string of the form session_. Raw request remains in /tmp/uap-additional-qoder-kimicall-fresh-ka537i9_/12768461663/members/provider-request-1.json. No session identifier needs to be copied into repository documentation. + +The current kimiAttemptRequest top-level allowlist excludes prompt_cache_key. The provider appends the raw request, validates that envelope, and returns400 on error before setting issued or producing its owned tool call. This source path plus the observed body identifies the first provider rejection. HTTP response bytes and the native empty approval response are not independently exported. The observed failed result, ordinary quarantine, SIGTERM cleanup and allfalse qualifications remain truthful. + +## Pinned primary-source basis + +Repository MoonshotAI/kimi-code, commit b8dd3a134060c6e80ba4a1659335cd63b68483f2. Source archive and exact Git blobs were read only; no vendor code was executed locally. Every cited file was verified against the complete pinned Git tree and its Git blob hash. + +- packages/agent-core-v2/src/workspace/sessionLifecycle/sessionLifecycleService.ts, blob b3eab53a221dca58aab5876a68d04da64da0e6f5: createSessionId returns session_ followed by randomUUID(). +- packages/agent-core-v2/src/agent/profile/profileService.ts, blob c73828a3be887c221ad16155898ecd52f9218ffe: model request params use this.sessionContext.sessionId as cacheKey. +- packages/agent-core-v2/src/llm-adapter/model/model-requester-impl.ts, blob83cc1cbde9c44724864b4f19a7ce73c96366673a: forwards params.cacheKey to the requester. +- packages/agent-core-v2/src/human/llm/requester/bases/openai/requester.ts, blob3726b5b38dace425ea3da588e53971991a6b1307: encodes an optional input.cacheKey. +- packages/agent-core-v2/src/human/llm/requester/bases/openai/format.ts, blob d074e9c1fb310d78f3dd1f497f28bb4481e2ed75: maps the value to prompt_cache_key. + +Source receipts, hashes and excerpts: /tmp/uap-additional-kimi-cache-key-source-thrtbnmr/cache-key-source-trace.json and session-id-source-trace.json. The field is request metadata, not a credential or tool ownership proof. + +## Exact intended change + +1. Extend only the Kimi single-tool test provider's known optional envelope fields with prompt_cache_key. If present, require a built-in Go string of exactly44 ASCII bytes matching session_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}. Use anchored bounded validation; reject null, booleans, numeric/array/object values, malformed/oversized/noncanonical strings. Absence remains valid for preserved inert requests and the source-supported no-cache case. Do not add other request fields or widen message/tool grammars. +2. Hold the first admitted request's cache metadata presence/value in provider state (empty string represents absence, because empty values are invalid). Require exact consistency on the second admitted completion request; added, removed or changed cache metadata fails before validating tool result or marking returned. This is an additional same-session invariant supported by the source's sessionContext binding. It does not establish equality to the native API session, which is not available to the Go provider at this stage; no such join will be claimed. Do not include raw values in errors or new diagnostics. +3. Preserve original bearer key, host/route/MIME/body/count limits, installed model/exact-one-tool declaration and schema, first-call no preexisting result, owned call ID/nonce/operation/marker, two-turn result validation, SSE framing, first-error latch and counters. Cache metadata cannot change any ownership or qualification decision. +4. Preserve client pin/config, default manual permission mode, actual approval validation/action, native service supervision, deadlines/poll count, artifact format/privacy/admission, original HOME/profile and whole-profile guard. No auth/trust/credential/pin/route/timeout/baseline workaround, fake hosted marker or local vendor execution. + +## Meaningful validation + +Before parser code changes, add a permanent inert regression with a fresh synthetic canonical session key and capture its failure against the old parser. Separately replay the unchanged genuine raw request through the old exact parser and the real in-process provider using a temporary test file; retain the assertion failure and exact raw hash. Do not commit the private/session-bearing raw request. Environmental setup failure does not count as RED. + +After implementation: +- Exact unchanged genuine raw request passes its envelope and reaches the existing owned first SSE response under a separately held inert provider credential. This is an inert request replay, not native execution or new end-to-end proof. Verify issued=true/returned=false, one captured request, unchanged raw bytes, one request count, no validation callback, expected owned call and no terminal completion. +- Permanent positive tests cover absent metadata compatibility and exact same canonical metadata through both real in-process provider turns, using the existing installed tool/nonce/marker facts. Verify original second-turn facts and terminal sentinel, request counts and no error. +- Permanent table-driven refusals cover wrong type, empty, prefix/length/hyphen/hex/case/control/oversized values and duplicate JSON key. Unknown fields/foreign tools/schema/duplicate JSON remain refused. Exercise the real provider path for representative invalid metadata, not only the helper. +- Second-turn changed/added/removed metadata refuses before result validation/returned. A later valid request cannot recover a refused provider. Verify source arguments, original model/tool/credential/route and counts remain required. Existing wrong-key/host/call/arguments/extra-turn tests stay intact; include metadata-bearing wrong-key, wrong route or foreign tool controls so metadata cannot bypass those gates. +- Run focused inert Go Kimi/provider contracts and existing relevant project-native contracts with no vendor opt-in. Serialized Go/lint slot; compile/test failures are recorded separately. gofmt and git diff --check. Affected all-enabled lint plus current six-linter gate. Read/replay the original failed artifact through the exact composed-source Python intake to confirm it stays failed/allfalse and keeps identical member bodies. No redundant broad test fan-out. + +## Review, publication and evidence boundary + +Record both exact pre-code GOs, RED/GREEN and final source manifest. Obtain two independent exact implementation reviews, fix actual findings, then compose with the separately reviewed scoped-selection and poll-diagnostic slices. Root alone performs normal expected-head fast-forward publication to existing PR524; no forced update, replacement PR, release or main merge. Actual hosted E2E after publication determines the next client state. Retain failures/unknowns without promoting artifact admission or source guidance to native qualification. VSCode remains deferred and unchanged. + +## Accepted before implementation + +Two independent GPT-6.1 Sol xhigh reviewers accepted corrected draft SHA256 `383c3df38324513560aca8c0d1cc878eb312c59668cfbb9429e9a11e9f633978`. The earlier draft mistakenly labeled the cache-value hash as the whole request hash; both reviewers verified the corrected original7839B body before granting GO. + +- `/tmp/uap-additional-kimi-cache-key-plan-R1.md`: SHA256 `8728c97e602b2177dfe3a9a3b50dc1220311917ef4fcfcd6f6d2649ab1aa6c6d`. +- `/tmp/uap-kimi-cache-key-plan-r2-review.json`: SHA256 `37651c4f69c89fd8def9101dee346eee709fe5cb20f657ea5df1bf6eb2d28c03`. diff --git a/docs/KIMI_PROJECT_NATIVE_COMPOSED_CORRECTIONS_VALIDATION.md b/docs/KIMI_PROJECT_NATIVE_COMPOSED_CORRECTIONS_VALIDATION.md new file mode 100644 index 000000000..a32a32021 --- /dev/null +++ b/docs/KIMI_PROJECT_NATIVE_COMPOSED_CORRECTIONS_VALIDATION.md @@ -0,0 +1,100 @@ +# Kimi scoped selection and native capture corrections: validation + +Composed source commit: `c1a3720f341ae2e746051bdcd2199567995627b0`. +Composed tree: `83ebe639b645e367d5b4707d27c64714d83027e8`. +Existing PR524 base: `b2bb2b7f85b5461420f932478b197905e6fc5ad9`. + +## Reviewed source and reason + +The genuine b2bb component capture completed repeat-add and unchanged update, +then showed intact repair planning removal of selected project MCP. Kimi's old +managed-selection policy always selected the user-format .kimi-plugin/plugin.json, +while its project artifact uses root mcp.json. Reading the wrong layout erased +recorded selection during repair preflight. The native byte-stability assertion +correctly failed and remains unchanged. + +Production fix `f09fbb1e52960c56e6b731aaf2aafc1c2aefd01b` adds an optional scoped +selection port and carries explicit held scope through the guarded usecase and +provider into Kimi's layout policy. It preserves the old user API/layout, optional +legacy ports, exact target/digest authority, both artifact verifications, original +profile checks and existing damaged-artifact reconstruction gates. A refused +scoped policy never retries a user layout. + +The same genuine b2bb single-tool capture preserved one completion request but +no owned tool call. Its original7839-byte request contains prompt_cache_key; +whole-request SHA256 is +`ddd8a402037716fe582f854dcf5d5dae1ebb902dc6b3a962466e4d34874c4de7`. +The old strict provider rejected that known client metadata before issuing the +owned first response. Exact pinned source proves generated session ID -> profile +cache key -> OpenAI request field. Fix `20921c06b3212f1243bde77f7d6cbbb35adcdeed`, +with Go1.22 test compatibility correction `30f5dfef137604b2a2367be2a125bb724fe6ab57`, +admits only the optional observed44-byte canonical string and requires unchanged +presence/value on the second turn. It grants no credential/tool authority and +makes no unobserved native API session join. Authentication, route, body/model/tool +schema, owned call/result facts, counts, SSE and first-error latch remain intact. + +Separately reviewed poll diagnostic `8311c8e9f571e9fa272abc2daed1a2f367ad160e` +retains only finite scalar facts at the original multiple-pending and exhaustion +failures. It preserves manual approval validation/actions, polling/timing, ordinary +supervision/quarantine and all qualification decisions. + +Each slice had two independent GPT-6.1 Sol xhigh plan GOs before implementation +and two independent exact code GOs after meaningful executor verification. The +composition preserves all20 reviewed source/document file hashes without conflict. +No native collector acceptance, native byte-stability gate, VSCode source, lint +configuration, authentication/trust setting or release policy was relaxed. + +## Actual inert validation + +- Old product: actual composed public CLI and public Engine intact-repair tests + failed on native skill/MCP byte changes. Current production source passes both + public paths, retaining explicit native MCP selection and persisted identities. +- Final frozen SDK intact-repair regression: PASS0.097seconds. Its complete user + and B tree comparison covers membership and file bytes, not mode/inode/link + metadata. Final affected whole-file lint and unfiltered six-linter gate:0issues. +- CLI, Kimi adapter, provider and usecase focused gates passed on the identical + reviewed files; both CLI lint gates reported0issues. Exact chronology and + earlier fixture/setup/test-helper failures are retained in executor receipts. +- Old provider: permanent canonical metadata regression plus original unchanged + request replay failed through the actual parser and actual in-process provider + with400 before issued. Corrected provider: exact original request reaches only + the expected owned first SSE response, with identical captured bytes and no + completed result/callback/sentinel claim. +- Final Go1.22-compatible provider contracts, including that unchanged raw replay, + PASS0.017seconds; both final lint gates report0issues. Controls cover absent/same + metadata,19 invalid type/shape values, duplicate JSON, unknown/foreign authority, + changed/added/removed second-turn metadata and inability to clear a refusal. +- Poll diagnostic:57 inert Kimi Python contracts and27 runtime contracts PASS. +- Original23-member failed single-tool artifact re-admits with identical bodies + and summary; all failure/qualification flags remain unchanged. +- Final composed-source Go compile and Kimi/shared CLI contracts PASS0.017seconds. +- gofmt, whitespace and exact reviewed-source hash comparisons pass. Session-bearing + transient replay files are removed from the source checkout; no raw session key + is committed by this correction. + +Retained saved-Git CLI lifecycle cases encountered the executor's missing +/proc/PID/task/TID/children capability before acquisition. That environmental +failure is preserved and is not counted as a pass; no ordinary containment guard +was changed. Genuine hosted CI retains that execution responsibility. + +No vendor/client/scanner process ran locally. Existing native component/single-tool +failures remain failed and unqualified. New actual disposable hosted captures must +establish the effect of the fixes and the remaining user/A/B lifecycle and MCP +boundaries. This validation does not claim authentication, real-model operation, +complete native qualification, main merge, release or deferred VSCode completion. + +## Exact review and executor records + +- `/tmp/uap-kimi-scoped-selection-f09f-source-manifest.json`: SHA256 `9ecb212ca8674580140ca55b7267ad359daf265ea010b576f799be72741a21d7`. +- `/tmp/uap-kimi-scoped-selection-f09f-code-R1.md`: SHA256 `7a0102a2b1dcd7d6a1eae04439a667faeab20df2202769c91760257e14da9acd`. +- `/tmp/uap-kimi-scoped-selection-code-r2-review.json`: SHA256 `bdcc89c716026c5f723812dee235c204f58b04bfbcf994e4dcbdb42b0df9d733`. +- `/tmp/uap-additional-kimi-cache-key-code-R1.md`: SHA256 `6a13e71db5947b89543b52e0b117c2230b6430f46ee991c1e26a7d1163ba91b9`. +- `/tmp/uap-kimi-cache-key-go122-delta-r2-review.json`: SHA256 `b75b3fa369d3e5ace1a11ded6b8b244801932b4353ef08ff56f6f833d9c836b5`. +- `/tmp/uap-additional-kimi-composition-code-R1.md`: SHA256 `d06ea64110f288d74de89f5fd97ee8ca9c39406167d4fba3918dc3a8434a67b9`. +- `/tmp/uap-kimi-composed-source-code-r2-review.json`: SHA256 `c208f636c5f22e1b654aa268b4b8e7682ed3696cf21d3d05b19d8b44f5d1f8ee`. +- `/tmp/uap-additional-final-serial-gates-1d4m_qyl/report.json`: SHA256 `1ca286a35b6c73e4dc32b6ef5525741aa8b323bb726ceda86968c06c017e00de`. +- `/tmp/uap-additional-final-serial-gates-1d4m_qyl/kimi-30f-report.json`: SHA256 `51053bf6d849d31679fe9be7f7cadc46fce654f961cdd6b1a8721f56d38e0a8f`. +- `/tmp/uap-additional-final-serial-gates-1d4m_qyl/kimi-composed-go.json`: SHA256 `9a3c437119aa1c945e2fbfe0fabc280387d63189c520d938825a9c3abc49d55e`. +- `/tmp/uap-additional-final-serial-gates-1d4m_qyl/kimi-call-unchanged-old-replay.json`: SHA256 `04ceb745d9019c529c3e2ed484a4575646fb567ea35c91b3d5a7586433140944`. + +Local paths identify this execution; committed source, plans and this validation document preserve the durable repository record. diff --git a/docs/KIMI_PROJECT_NATIVE_CONTEXT_REFUSAL_PLAN.md b/docs/KIMI_PROJECT_NATIVE_CONTEXT_REFUSAL_PLAN.md new file mode 100644 index 000000000..0f2e56e81 --- /dev/null +++ b/docs/KIMI_PROJECT_NATIVE_CONTEXT_REFUSAL_PLAN.md @@ -0,0 +1,123 @@ +# Kimi: exercise the actual profile snapshot adapter and classify its refusal + +## Measured current failures and source certainty + +Published identity-parity head499a694729e03d56cab843e7b94ea840a71295d8 +has tree41554ec446b33cb8997e26ace18b3902c828ba71, identical to localb6fe441b. +Preserve that separate role projection and all prior host/profile/schema/pin/ +supervision/ownership changes. This new slice does not revise or combine them. + +Genuine preceding b7235fb3a7084a6f1e293676c201dc4fd86f2515/tree143c1e96 +run40461197005 passed admission, then both native jobs failed before a service: + +| Job / artifact pair | Exact current captured boundary | +| --- | --- | +| components122047731757, native12715247415/frontend12715366882 | observe-empty exit1/error=false/deadline=false/stdout0; installed/context/enter/validation, observer_entered=false/service_recorded=false/cleanup all null | +| single-tool122047731730, native12714519282/frontend12714469374 | native-attempt exit1/error=false/deadline=false/stdout0; single-tool/context/enter/other, same unreached service/cleanup | + +Native/frontend outer SHA256 values are respectively +0f1dc9fe1cef13cf4cbb0935e94e3d108f11c5ffe0899e67797734a0fa149044 / +792d786b7dc260ff13365ef3129b3f5a17ea729d2055f74b9c6fec2b07b0a13b, +and56b68ce6733b06ea5ee7eeb53999102fcba67c15b206ad54e6faedacc6582c82 / +d5465d4daad3c781e93dc54939175225c6674b6cb33da4546a8824f410e08583. +Closure is16/25 and21/25 canonical unique ordinary members with CRCs; both +frontends have24 verified stream byte/hash joins and exact committed source/ +tree/clean streams. All qualification/auth/model flags remain false. Detailed +audit.json and raw files are under /tmp/uap-shell-fresh-oct27//. + +The source-proven single-tool defect is concrete: its new context-stage +comprehension refers to os.environ, but kimi_attempt.py never imports os. +Thus that adapter has an unresolved NameError before calling the helper. The +earlier inert positive directly called attempt.kimi._installed_environment, +so it did not exercise this actual process-environment snapshot expression. +Own and correct that coverage gap; AST parsing alone cannot detect this name. + +The component's captured validation refusal does not identify whether it came +from held-key comparison, private directory owner/group/mode or a stability +check. Do not infer an actual directory mode/owner or weaken any predicate. +This slice measures only that finite refusal before choosing a later fix. + +## Finite correction and diagnostics after two independent plan GOs + +Scope: the two existing Kimi collector Python modules, their existing two test +modules and this plan. No Go, production adapter, shared service/profile factory, +native API grammar, source pin, account/trust policy or qualification change. + +Centralize the existing explicit12-key os.environ snapshot in one tiny private +adapter in kimi.py, which already imports os. Both installed entrypoints call +that actual adapter, which delegates to the unchanged strict existing-profile +environment validator. Remove the undefined os reference from kimi_attempt.py; +do not introduce a bulk inherited environment or a second profile recipe. +The exact12 selected values, fixed controls and original no-write/nofollow/ +UID/GID/0700/stability/checked-close refusal remain identical. + +Make those existing private profile refusal sites raise a small internal typed +ValueError carrying only a closed role/reason and, when actually held, bounded +directory metadata. Roles are the12 static environment key names, root/home/ +tmp/four XDG roles, common-ancestor or descriptors. Reasons are finite key-set, +missing/type/value, canonical, open/type/uid/gid/mode, held/linked identity or +close categories. Unknown roles/reasons/metadata refuse diagnostic rendering. +Never capture a raw key/value, path/component/link target, credential, file body, +error string/repr or guessed errno/root cause. For an open failure, report only +the known role and fixed open category; do not read an unsafe node for metadata. +The typed wrapper preserves the safe original exception category: caught +OSError/open/close failures remain exception_kind=os; explicit existing +ValueError predicates remain validation. Validate this finite category in the +constructor/classifier; attaching metadata must not relabel an OS failure. + +Only when a held directory stat already exists may metadata include its +permission-mode integer (bounded0..07777) and exact booleans for ordinary +directory, current UID equality and current GID equality. Otherwise omit those +fields. No new filesystem reads, fallback, writes, mode repair or policy waiver. +The ordinary common ancestors retain type/no-follow/stable binding checks; +private0700/UID/GID predicates remain limited to the selected fixture dirs. + +The existing bounded private failure line may include one optional exact +profile_refusal object only for this typed internal exception. All strings are +finite literals and metadata has strict types/bounds; the existing2KiB limit, +generic quarantine failure, stdout0, first failed action/last action behavior, +truthful service/cleanup nulls and all other exception categories remain. +Other failures have no such object, and malformed diagnostic state must leave +the original failure/quarantine intact. No diagnostic can accept a failed run. + +## Meaningful source-only verification and remaining hosted proof + +Invoke the new actual snapshot adapter through both modules' production call +paths with real owned Go-layout directories and only the12 real test-profile +environment values. Do not set hosted eligibility or bypass a positive guard. +Assert exact output/no mutation/no unrelated ambient private/proxy/loader +inheritance; this exercises the missing-name seam that the prior helper test +missed. Both mains must call that exact extracted snapshot seam under test; +directly testing _installed_environment again is insufficient. Keep the real +entrypoint negative hosted guards unchanged. + +Use actual held wrong-mode/symlink/missing/replaced directory cases and finite +mocked UID/GID comparison controls to verify exact role/reason and only held +metadata. A private exception/value/path/target canary must never occur in the +serialized optional object. Malformed role/reason/type/bound controls suppress +diagnostics while keeping failure. Existing key-set, held identity, complete +descriptor closure/close-error and unchanged private configuration tests remain. + +Run the complete existing collector/single-tool/shared-supervisor Python suite, +new actual-adapter and finite refusal controls, AST and diff checks. No Go or +native client/model/positive hosted guard is needed. Obtain two independent +code reviews, then root alone publishes to existing PR524 on a fresh lease. +Require a genuine source-bound follow-up to identify the component's actual +context condition and advance the single-tool adapter. Later source/ownership +or API amendments still need their own measured plan; full lifecycle, MCP and +cleanup qualification remains mandatory. No release/new PR/VS work. + +## Completed local validation + +Both independent plan and complete code reviews approved the exact four-file +correction. The actual twelve-key process snapshot adapter is now exercised +from both installed modules, including repeated no-mutation/private-canary +controls. Nine focused real profile/adapter/refusal contracts passed (0.053s). +The complete collector, single-tool and shared-supervisor suite passed all56 +tests (16.650s); root independently reran all44 Kimi module tests (3.962s). +All four Python ASTs and diff whitespace checks passed. Finite role/reason and +held metadata controls verify mode/owner/group/open/close failures, original +os category, null unreached cleanup, bounded output and malformed-state refusal. +No Go, vendor/native client, model or positive hosted guard was executed. +The component's actual context predicate is still unclaimed until a new genuine +source-bound capture reports it; none of this promotes the old failed evidence. diff --git a/docs/KIMI_PROJECT_NATIVE_CURRENT_REFUSALS_VALIDATION.md b/docs/KIMI_PROJECT_NATIVE_CURRENT_REFUSALS_VALIDATION.md new file mode 100644 index 000000000..c704a06b7 --- /dev/null +++ b/docs/KIMI_PROJECT_NATIVE_CURRENT_REFUSALS_VALIDATION.md @@ -0,0 +1,109 @@ +# Kimi current repeat-add and approval refusal validation + +## Reviewed source and authority + +The source for the current genuine failures is PR524 commit +`03d7c243129c98ecdc4cbb99bfe1a47536a556bf`, tree +`de7a5565545f67e26e7e3e101b843f728e3876b1`, runtime +[40553154543](https://github.com/777genius/universal-agent-plugins/actions/runs/40553154543). +The component and single-tool jobs both failed; all five qualification flags +remain false in both native and frontend captures. The complete current API +check set was 44 successful, two native failures and one skipped check. + +Both exact proposals received root R1, independent desktop R2 and a separate +native CLI plan review before implementation: + +| Proposal | Approved SHA256 | +| --- | --- | +| Repeated-add direct result | `c709b9d3390263eb602ac1781090b1c0b8f48811c10c0c6696ee8aeff2d38e62` | +| Approval refusal finite facts | `e841ca2be7330be91b787f2a4a015c6a0a329b529cf16a55404921d40c7bbcf1` | + +The changes remain separate commits: +`4b420105115d66b6b9dfabb54b3d777611d4ddc3` implements the exact repeated-add +result contract; `a58aba727c613a2f2b5f129f0acfecfb20c234c7` implements only +failure diagnostic facts. Native CLI and desktop reviewers independently +approved the first code at tree `ce7d293580faf433844c9b64f6b52456a04b3199`; +the desktop code GO covered the same executable bytes before a comment-only +truthfulness correction. Root, native CLI and desktop reviewers independently +approved the second at tree `bcee7cdf3c5b509676118b6346ee40f7999617e4`. +Final validation notes changed no executable bytes. + +The strict approval function's AST is identical to the published function +except for its private name. Its exact turn0, identity, permission and schema +predicate order remains intact. ResponseSchemaRefusal retains its exact +object/class and existing graceful branch. The diagnostic grants no approval +or tool authority and exports no native values, identifiers or hashes. + +## Genuine failed captures retained unchanged + +All four current artifacts were freshly downloaded again after the interrupted +publication session. Size and SHA256 matched the current GitHub API receipts; +every ZIP byte equaled the previously reviewed copy. Nested CRCs, closed member +inventories, extracted bytes and frontend stream joins remain valid. + +| Artifact | Members | Outer ZIP SHA256 | +| --- | ---: | --- | +| Component native 12759050559 | 34 | `01d59c89fe8124ec17d2ab08f5239e746e23d2c0db7876e34ba482885cef4ffb` | +| Component frontend 12759450014 | 25 | `b8163211655fe5215607758975694968dd05bc67c24c3b26a014b599a7ec9aae` | +| Single-tool native 12756894604 | 23 | `80fdf584518a9f2d879c61ce0eb12eb8b4b6adcbaa1fc1028c188399406422ac` | +| Single-tool frontend 12758701279 | 25 | `443be84f49ffa69c4e789d0cd33b7bd27c71d45ae3f6571af887486c69c3cf80` | + +The component capture passes its installed observation, then refuses the +successful direct repeat-add result in the fixture's old array-only parser. +The single-tool capture refuses at approvals/validate/validation before any +approved tools/call. Its raw approval values remain quarantined and unobserved; +this correction does not claim which remaining predicate differs. + +## Current-base alignment and final inert gates + +Commit `29f93abe9739d65336a39a81fc082ce238b5dfa1`, tree +`bbf6199df0628636c81bb719a80005a07c90ab3f`, is a true merge of the reviewed +candidate and current PR520 base `a412ba5e137fdcb7e004393229b323211ed746e1`. +All six Kimi code/test files below remain byte-identical to the reviewed leaf. +The only manual conflict retained both append-only consolidated-plan blocks +verbatim. Independent native CLI review verified the full nonconflicting tree +union, every nonblank parent plan line in order and the automatic detector-test union. +The shared runtime Python source/tests are byte-identical to the Cline-qualified +base. A final documentation-only cleanup removes one inherited extra blank EOF +from KIMI_PROJECT_NATIVE_HOST_MARKER_HANDOFF_PLAN.md. + +| Check | Actual result | +| --- | --- | +| Focused Kimi/proof/single-tool/shared native CLI Go, before base merge | PASS 0.392s | +| Actual current repeat-add stdout against separately held first-add identities | PASS 0.009s | +| Complete Kimi collector/single-tool/supervisor Python | 65 tests PASS 17.727s | +| Focused Go after true base merge | PASS 0.620s | +| Kimi/supervisor/shared-runtime Python after true base merge | 92 tests PASS 23.859s | +| All configured root linters on affected lines versus actual a412ba5e | Zero issues | +| Unfiltered root revive/funlen/gocyclo/gocognit/dupl/depguard | Zero issues | +| Strict approval AST comparison, changed Python AST, gofmt and final diff checks | Clean | + +The raw replay was a temporary inert Go control; it was removed before final +lint. It also confirms that the unchanged shared array parser still refuses +the actual direct result. No raw capture is committed. Local child processes +were inert test processes; no vendor/client or public installer ran locally. +Go1.26.10 and golangci-lint2.13.2 ran in a coordinated exclusive slot with +GOPROXY/GOSUMDB off, the existing module/cache paths and the unchanged linter +configuration. Python used the existing complete inert suites. Final lint +receipts are `/tmp/uap-kimi-postbase-affected-lint.json` and +`/tmp/uap-kimi-postbase-whole-six-lint.json`. + +| Reviewed code/test file | SHA256 | +| --- | --- | +| repotests/agentplugins_kimi_project_native_lifecycle_test.go | `b6cc4cf42b1e425f0ce9b801d5475fdc9810b485daed983466cf24cc63e844ba` | +| repotests/agentplugins_kimi_project_native_repeat_add_test.go | `bb0c1d30455efbccb32fd19290909dc64d275d995ccbfe4258b75547bee5e130` | +| scripts/project_native_collectors/kimi.py | `e772cb0d2c2b7a3bdc290f061d1dab8310a1fe7f9a3e35ef02751e8aa91448e9` | +| scripts/project_native_collectors/kimi_attempt.py | `420509c0101c708ac26fa836f23753441381cbf926e368fa18d8e2c61f442000` | +| scripts/project_native_collectors/kimi_approval_facts.py | `fe829a905c18ee33ee08f6266d89b00b5c852b8a3efe7727860de2d638988ee7` | +| scripts/test_project_native_kimi_attempt.py | `c3b6c38108516f3d4d037c2c8a18e260236c2a953a5644884c190cd4c51e93c6` | + +## Remaining native gates + +Root alone publishes after a fresh expected-head check. A fresh genuine hosted +component run must establish the later update, repair, restart, removal and +preservation stages. The separate single-tool lane still requires its native +approval/history evidence and a separately reviewed finite history grammar; +its deliberate final failed-capture boundary is unchanged. No account/model, +release or VS Code qualification is added. The original 900s Kimi lifecycle +suite, admission, pins, ownership, provider and cleanup limits are preserved. +Historical failed artifacts are never relabeled as results of this candidate. diff --git a/docs/KIMI_PROJECT_NATIVE_EXISTING_PROFILE_CONTEXT_PLAN.md b/docs/KIMI_PROJECT_NATIVE_EXISTING_PROFILE_CONTEXT_PLAN.md new file mode 100644 index 000000000..e0621a844 --- /dev/null +++ b/docs/KIMI_PROJECT_NATIVE_EXISTING_PROFILE_CONTEXT_PLAN.md @@ -0,0 +1,147 @@ +# Kimi installed observers: reuse the actual existing profile without provisioning + +## Current source and measured boundary + +Published PR524 head705fa429eaad9403113f4fcddb57d3a4f99c96ba has +treee8d9fa5d0a6adc90aee91f7032a1cddec1b3af3e, identical to reviewed local +62ea70f4b2e3c7589cab2fbae774345fcf2d6ca3. Preserve its genuine held-marker +handoff and every prior external schema/Windows/context and Python diagnostic +change. This follow-up addresses the distinct installed-component context +failure; it does not claim the single-tool run has passed its later gates. + +At previous source55f5d848fb61899f2c84bd7cccc7592549718b5f/tree2f20a8e8, +runtime40456546065/job122031436251 completes observe-empty and all four public +add operations, then observe-installed exits1/error=false/deadline=false with +stdout0. Its exact401-byte stderr SHA256 is +6ef2c6c28e6dce941d029cc2dd3d6a233b17594c75a78dd9b3e15d6174107741. +The finite diagnostic says installed/context/enter/os, observer_entered=false, +service_recorded=false and all cleanup values null. No later API/service ran. + +Closed native12713940918 outer SHA256 +5a59f0a45ca0139e9cd3ad26e8840adbc9aee4b2e160f3bf863e9c0510ffbef4 +and frontend12714100073 outer SHA256 +2d7907fd2d633c5fbf8207f90b378a1329da9ac548205e52c558f91ef64af859 +have31/25 bounded canonical unique ordinary members, verified CRCs and exact +committed source/tree; all qualification flags remain false. Separate read-only +research40456546030 succeeded with complete source-bound capture, not lifecycle +or MCP qualification. + +## Source-derived cause and original profile authority + +At exactly the context stage, both installed Python entrypoints call +shared.legacy.runtime_environment(home, root/tmp). That is a fresh-profile +factory: native.profile_environment unconditionally mkdir's home/config, +home/cache, home/state, home/data and home/npm-cache, then writes fresh empty +npm/git configuration files. Repeating it after observe-empty necessarily +encounters its existing first directory. A source-only inert temp-directory +reproduction of two calls produces FileExistsError before any service. The raw +capture establishes only context/OSError, not the private exception text or +filesystem body; the narrower FileExistsError diagnosis comes from this actual +source path and deterministic inert reproduction. + +The Go-owned original fixture already creates ordinary home, tmp and +root/xdg-config, root/xdg-cache, root/xdg-state and root/xdg-data directories. +Its closed environment supplies those exact original XDG paths, while the +fresh-profile factory chooses different home/config-style paths. Reusing that +factory with exist_ok, deleting directories or truncating existing profile +files would neither preserve the original environment nor prove ownership. +Installed observation must consume the actual already-created Go-owned profile +without creating a replacement or adopting a native rewrite. + +## Finite nonmutating environment handoff after two plan GOs + +Scope is scripts/project_native_collectors/kimi.py and kimi_attempt.py, their +two existing inert test modules and this plan. No shared research/profile +factory, supervisor, production adapter or Go fixture change. + +Add one Kimi-only private helper used by both installed entrypoints. It accepts +the already request-validated root/home and a closed mapping of exactly12 held +environment values. Each caller reads only these named os.environ entries; +never copy os.environ or accept arbitrary extra keys. Validate exact string +types, keys and equality against the existing Go fixture authority: + +| Held key | Required value from the existing fixture | +| --- | --- | +| HOME, USERPROFILE | exact request home, which is root/home | +| TMPDIR, TEMP, TMP | root/tmp | +| XDG_CONFIG_HOME | root/xdg-config | +| XDG_CACHE_HOME | root/xdg-cache | +| XDG_STATE_HOME | root/xdg-state | +| XDG_DATA_HOME | root/xdg-data | +| GIT_CONFIG_NOSYSTEM | exact held value1 | +| GIT_CONFIG_GLOBAL | exact original os.devnull path | +| GIT_TERMINAL_PROMPT | exact held value0 | + +Return those validated held strings, rather than synthesizing a different +profile. Retain the existing observer's fixed PATH=/usr/bin:/bin, LANG=C.UTF-8, +NO_COLOR=1, TERM=dumb and KIMI_CODE_NO_AUTO_UPDATE=1 controls. No ambient PATH, +credentials/tokens/provider/proxy/loader settings, host eligibility markers, +unrelated application state or npm configuration enters the vendor child. +The original Go command environment remains unchanged; the private provider's +already-authored HOME/.kimi-code config and recorded original HOME stay exact. + +Before returning an environment, check root/home/tmp and each four existing XDG +directories through held descriptor-relative O_DIRECTORY/O_NOFOLLOW traversal. +Require canonical exact paths, current original UID/GID, ordinary private +directories and stable held/linked identities with checked closes. Refuse a +missing directory, alias, wrong owner/type/mode, replaced ancestor or any +inconsistent held value. No mkdir, writes, unlink, chmod, repair, config-body +read, alias resolution or fallback is allowed. Validate only the finite existing +directory set; do not traverse arbitrary profile contents or user credentials. + +Replace only the two calls to the fresh-profile factory at the existing +context stage with this helper and the explicit held mapping. The general +read-only research lane still uses its unchanged fresh-profile preparation. +Preserve both independent real hosted/platform guards, every existing API/ +provider/probe/receipt check, original budgets, diagnostic/quarantine behavior, +permission/trust policy and actual cleanup requirements. No later failure is +accepted or relabelled by this correction. + +## Meaningful inert contracts and genuine follow-up + +Use real owned temporary Go-layout directories and the actual new helper, +without setting any hosted marker or invoking a native guard/client. Compare +the complete finite output to independently expected held values; inject +unrelated ambient private/proxy/loader canaries and require their absence. +Call the helper repeatedly with existing original profile directories and +private sentinel/config files; verify exact full held metadata and bytes stay +unchanged and no home/config-style replacement directories or npm/git files +are created. Preserve an existing nonempty original git/npm/config sentinel; +the helper must not open, truncate, repair or adopt it. + +Negatives cover each wrong/missing/nonstring/extra held key, foreign home/tmp/ +XDG paths, absent/regular-file/symlink directory, aliased ancestor, changed mode, +and mocked finite wrong UID/GID plus deterministic held/path replacement at a +validation boundary. Every failure returns no partial environment, performs no +write. Invoke the actual helper with both installed entrypoints' finite input +shapes and review both sole context-stage call sites to ensure neither calls +the old factory or launches a service before validation. Do not bypass/mock a +positive native hosted guard in order to exercise a local entrypoint. The +actual negative hosted-guard tests remain unmodified and active. + +Run the existing complete Kimi collector/attempt/shared-service Python suite, +new ownership/nonmutation controls, AST and diff checks. No Go or vendor/model +execution is needed. Independent code reviews precede root-only publication to +existing PR524. No pin, public mutation, auth workaround, release/new PR or VS +Code work. Require fresh genuine source-bound runs to pass unchanged context +admission and expose the next actual boundary; full lifecycle, restart/removal +and MCP qualifications still require their complete native evidence. + +## Completed local validation + +Both independent plan reviews approved this finite existing-profile handoff. +Code review required removal of an added Path.resolve call from the new helper; +the final helper uses lexical canonical checks and held no-follow traversal. +The original earlier request guard remains unchanged. Tests explicitly forbid +Path.resolve while exercising both an unchanged original profile and a matching +alias-shaped environment, so an alias cannot be silently resolved into authority. + +All 54 collector, single-tool and shared-supervisor tests passed on the final +bytes (16.459s), including real owned temporary directory nonmutation, exact +held environment controls, missing/wrong keys, type/mode/owner/group refusal, +symlink/ancestor rejection, deterministic held-directory replacement, complete +descriptor closure and failed-close refusal. All four Python ASTs and diff +whitespace checks passed. These checks ran inert source contracts and the +existing private supervisor child; they did not set eligible hosted markers or +execute a native client, installer or model. No Go was needed. Genuine +source-bound hosted context/API/cleanup and full lifecycle proof remain required. diff --git a/docs/KIMI_PROJECT_NATIVE_FAILURE_STAGE_PLAN.md b/docs/KIMI_PROJECT_NATIVE_FAILURE_STAGE_PLAN.md new file mode 100644 index 000000000..b8c48ca07 --- /dev/null +++ b/docs/KIMI_PROJECT_NATIVE_FAILURE_STAGE_PLAN.md @@ -0,0 +1,156 @@ +# Kimi installed collectors: finite failure-stage diagnostics + +## Fresh actual failure and controlled source + +PR524 current published source a4a211d60595abbb8592e76e27846ba6c349a6d0, +tree975a0faff2689474fe9b6d07c663af0fec78933a, has runtime40452608070. +Both jobs now pass public installation and the corrected receipt/schema proof. +Component122018618870 completes user/A/B/C adds, then observe-installed exits1 +with zero stdout and only "Kimi installed API observation failed; private capture +quarantined". Single-tool122018618873 completes A add, then native-attempt exits1 +with zero stdout and only "Kimi single-tool observation failed; private native +streams quarantined". Neither capture reveals the failing callback operation, +exception category or nested service cleanup result. No HTTP shape or specific +root cause can be inferred from those generic diagnostics. + +Native component12711270709 outer SHA256 +b898629adf03caef42df54afaa4a394b4ccaf63bcbe59bb7300c3f4e44579e10; +native call12711270602 outer SHA256 +12fbc3c6083f530393aee3196c7af3e493d29b7fcd5717414fe0e77938b25abc. +Matching frontends12711445369/12711380421 were independently checked with the +native archives for exact outer hashes, bounded canonical unique ordinary ZIP +inventories, CRCs, exact committed source/tree and empty patch list. All five +native qualification flags and vendor/model flags remain false. Core40452608159 +and Terminal40452608141 now pass; they are not native-runtime qualification. + +Local work/kimi-a4-diagnostics baseline7e10e7da7a883c8c371d837e37a99b331fbc3b54 +has exactly the current published tree975a0fa. It was reconstructed from the +earlier exact tree31a95 plus all six immutable official current-file blobs; +each full git-blob hash and the complete resulting tree were asserted. Preserve +all six externally published schema/Windows/noctx files byte-for-byte. The old +local schema/noctx plan/code sequence through5ac10bf remains on its original +branch and is not transplanted onto this baseline. + +## Existing capability inventory: preserve, do not republish blindly + +The earlier local4406458a finite ResponseSchemaRefusal capability is already +byte-identical in this current published tree: kimi_attempt.py SHA256 +326d4daf8682ad3a85f5251b551cc354a21d330ae4ac092d36c9905558d8e0ef, +test_project_native_kimi_attempt.py SHA256 +8cac1d82093c87e73ba0439325888b3014a251c1d174b8f64236af5e99f69649. +It catches only registered later session/prompt/approval/snapshot/history shape +refusals, stops later tool actions, obtains the same graceful shutdown/reaping +and emits only the existing admitted redacted closure with failure status. +Authority/permission/readiness/transport/cleanup errors remain quarantined. +Preserve that implementation and its meaningful inert supervisor tests. Do not +broaden its catch, expose quarantined HTTP or treat this new generic failure as +a known ResponseSchemaRefusal. + +## Diagnostic-only implementation after two independent plan GOs + +Scope is the two existing collectors scripts/project_native_collectors/kimi.py +and kimi_attempt.py, their two existing test files scripts/test_project_native_kimi.py +and scripts/test_project_native_kimi_attempt.py, and this plan/validation record. +No Go, shared service/frontend, provider, native grammar or authority file changes. + +Add one small Kimi-only failure tracker in kimi.py, reused by the existing +kimi_attempt import. It stores only a registered stage, registered phase, a +finite safe exception category and boolean reached status. Its report must be +constructed from an explicit closed schema, never an arbitrary dict/object. +Do not include exception str/repr/traceback/class name, native output, request +or response bytes/keys, URL/path, bearer/key, nonce, session/call/workspace ID, +stdout/stderr, environment, filenames or user-supplied request.stage. + +The finite stage inventory covers main host-admission, request-read, +request-validate, authority, immutable-closure, context, service-entry, ready, +meta, health, unauthorized, workspace-a/b/c, trust-before/set/after-a/b/c, +trust-untrusted-c, catalog-a/b/c/user, mcp-outside, mcp-a/b/c, skills-a/b/c, +test-a/b, test-refused-c, probe-events-a/b/c, distinct-workspaces, pre-call, +create-session, prompt, approvals, approve-once, snapshot, history, +preserved-authority, shutdown, service-cleanup, serialization and emission. +Only the stages actually used by each collector are instrumented. The repeated +approval/snapshot indexes remain private and map to their single registered +stage. Phase is one of enter, request, envelope, validate, complete. Unknown +stages/phases cannot be rendered; registration errors fail closed. + +Before an existing API operation mark its finite stage/request; after the same +bounded service.http returns mark envelope, and before returning its validated +envelope mark validate so the existing caller's strict object/value checks are +attributed to that operation. Mark readiness/authority and the existing +non-HTTP checks at their actual boundaries. A wrapper around each existing +observer callback records only the safe category of an uncaught exception +before the unchanged Service swallows it; it rethrows that same exception. +If the callback returns normally, mark service-cleanup before the unchanged +Context.service completes supervision and immutable rechecks. Do not catch a +failure and continue to another HTTP, approval, prompt or tool action. + +Safe exception category comes from a finite type mapping (validation, type, +key, OS, timeout, other), with no dynamic type/module names or message. The +original failure/exception and return-code behavior remains unchanged. +Callback-entered is true only if that wrapper was actually entered. A recorded +service result is reported only from the actual existing Context summary +command, not inferred from a generic failure. + +On the existing generic entrypoint exception branch, emit one bounded line of +static-prefix JSON to stderr (maximum2KiB), followed by the unchanged generic +quarantine failure. Report the finite stage/phase/category, observer-entered, +service-recorded and these five cleanup values copied only when present as +exact bools in the actual Service result: shutdown_acknowledged, sigterm_sent, +forced_kill, group_reaped, port_closed. Missing/unreported values are null, +with cleanup_reported=false; never turn unknown into success. Do not serialize +any other service or Context field. No new stdout envelope or artifact member +is added for generic failure. Existing stdout quarantine and the original +closed evidence/secret checks remain unchanged. + +Do not emit a new failure report on success or alter the already supported +ResponseSchemaRefusal path. Preserve its failure return1 and redacted graceful +capture, existing API budget/reserved shutdown slot, original hosted guard, +150/60/65-second budgets, process signals/reaping, endpoint and credential +authority, request inventory, trust/permission/manual approval, source/pins, +cleanup/admission and all qualification flags. This slice identifies a failure; +it does not accept or repair it. + +## Meaningful verification and publication + +Extend the existing inert tests with failures containing planted bearer/key, +path, nonce, session and arbitrary exception text. Exercise the actual tracked +collector callbacks and their existing inert service supervisor where possible, +then render the failure line and require the exact closed fields/enums, finite +size/no raw linebreak, no private value/exception text/HTTP body and failure +status. Cover pre-service failure (no cleanup claim), readiness, HTTP transport, +strict envelope/validator, permission/authority and post-callback cleanup +failure. Compare cleanup booleans with the actual retained supervisor record, +including false and unavailable values. Verify the first failed operation is +the last attempted action; no extra API, grant, prompt or tool is introduced. +Unknown stage/category inputs and malformed cleanup dictionaries cannot cause +arbitrary data to enter stderr. + +Keep and run all existing Kimi collector/attempt and shared service inert +contracts, including actual inert Python child cleanup/quarantine tests and the +previous finite-schema-refusal graceful capture tests. These are not native +Kimi/model/provider observations and require no Go slot. Run Python syntax and +whitespace checks and independent code review before root-owned publication to +the existing PR524. No vendor binary executes locally, no host spoofing, new PR, +release or VS Code work is included. + +Fresh genuine hosted source-bound component and call captures must identify +the actual failed stage/category and truthful cleanup status before any later +behavioral or grammar amendment is planned. Do not relabel the existing failed +runs, assume a response schema mismatch or promote any native qualification. + + +## Actual implementation validation + +The exact four-file candidate passes all 47 existing/new Kimi collector, +attempt and shared service inert tests in 16.404 seconds, including the +existing graceful finite-schema refusal and actual inert Python child +quarantine/reaping tests. All four Python files parse; whitespace checks are +clean. The six externally published Go files remain byte-for-byte unchanged. +No vendor binary or Go process ran. + +The first run's precise transport-stage assertion exposed an existing inert +test fixture issue: a null selected response stage also matched unregistered +health operations and inserted an unknown field too early. Requiring a +non-null selected stage restores the intended transport/permission/cleanup +negative controls; it changes no collector or native response grammar. The +complete final rerun above passes with that meaningful fixture correction. diff --git a/docs/KIMI_PROJECT_NATIVE_FINITE_COMPLETION_VALIDATION.md b/docs/KIMI_PROJECT_NATIVE_FINITE_COMPLETION_VALIDATION.md new file mode 100644 index 000000000..3fe1dbab2 --- /dev/null +++ b/docs/KIMI_PROJECT_NATIVE_FINITE_COMPLETION_VALIDATION.md @@ -0,0 +1,236 @@ +# Kimi finite single-call completion + +Implementation of the accepted pre-code plan in +[remaining native qualification](plans/project-install-e2e/remaining-native-qualification.md) +(plan SHA256 fb44cab8565ed9023f43ce45a0e2d1c8d5f06ea03cd9c0118b092003c151aaa7). Root and an independent second +reviewer accepted the exact plan before source changes. Validation and fresh +native qualification for this implementation are pending. + +## Measured starting point + +Published source9e9779f2352101e8002070ac64ac30d24e2f9be5, tree +a77b1de54dfbc16522f603265a74954615be2bc4, hosted run40586437481: + +- Component job122491615607 passed36.951seconds. Independently audited native67 / + frontend25 members,24frontend stream joins,14service stream joins,126HTTP joins, + seven fresh native servers and eleven initialize/list probe sessions. The four + component flags are true; tools/call, vendor authentication and real model are + false. This component implementation and its reader remain unchanged. +- Single-call job122491615779 failed8.164seconds. Its original25-member native + archive and25-member frontend archive remain external audit inputs; no measured + raw capture or log is added to the repository. The actual collector exited0 + with ordinary shutdown, one matching manual approval, three correlated probe + events and two provider requests. Its second returned tool message includes + the exact native wall-time line before JSON. Native history ends with a failed + turn and empty assistant. All original flags remain false. + +The immutable native2.3.2 tag resolves through annotated tag7aa8fa1eab3557ffac521a2139e4dd6583f70f58 +to primary sourceb8dd3a134060c6e80ba4a1659335cd63b68483f2. The accepted plan records +verified Git blobs for model rendering, native session/message/snapshot schemas, +message projection/history order and the first-session date reminder. No native +or public installer/scanner execution occurs locally. + +## Implemented boundary + +The model-visible facts path requires one exact anchored native +`Wall time: D.DDD seconds` line, finite0..60seconds, then one whole bounded strict +JSON document. The raw native-history/probe JSON path stays unframed. Existing +nonce, revision, argv, managed root/data, marker and fresh PID/session/event joins +remain mandatory. No brace search, arbitrary prefix/suffix removal or alternate +protocol is introduced. + +The Python native observer remains capture-only and byte-identical. An independent +pure Go verifier validates its closed native service/HTTP evidence, byte/digest +joins, fixed endpoint sequence, one owned manual approval and finite native +history. It requires a terminal completed session with no in-flight turn, +pending interactions or subagents; the exact owned tool_use and successful raw +tool_result; the final own sentinel; and exact reverse-order identity between +complete terminal snapshot and history. The optional date reminder has the +source-defined closed metadata and text. Additional or unfamiliar native shapes +remain refused. The original measured failed history is never promoted. + +Success also requires the observed marker and unchanged remaining data inventory, +all original immutable/foreign authority guards, and ordinary bounded provider +shutdown inside the original150second work/180second total origin. Failure clears +staged proof/completion and every qualification flag before serialization. + +The single-call success pair has exactly three true flags: mcp-initialize, +mcp-tools-list and mcp-tools-call. Project-lifecycle/native-restart-removal remain +false in this lane. Activation stays Prepared; vendor authentication and real +model remain false. Component evidence is independently qualified and must not +be copied into this lane. + +## Closed marker/data evidence + +The only new optional failed/successful artifact member is the fixed ordinary +UTF8 JSON file `native-data-proof.json`, within the existing1MiB member/total +capture bounds. It is emitted only after the live fixture has read the exact +expected marker and compared the original owned data inventories. No unknown +file content, user profile content or credential is exported. + +The exact schema has six fields: + +| Field | Shape and check | +| --- | --- | +| schema_version | Integer1. | +| before | Already-held owned data path/mode/digest map; at most4096 entries and32 levels, canonical relative paths, original root and owner file required. | +| after_without_marker | Independently observed same map after removing only the exact owned `native-marker.txt` entry; structurally equal to before. | +| marker_body | Exact observed expected `retained-` text, at most256bytes. | +| marker_bytes | Exact UTF8 byte length. | +| marker_sha256 | Recomputed SHA256 of observed marker text. | + +The typed native-history proof adds `data_proof_sha256`, recomputed over this +entire raw member. Both Go and Python success readers recheck inventory equality, +canonical parent closure, marker text/length/digest and proof digest; no true +boolean substitutes for these joins. Success has exactly26 members. A later +failed capture may retain this member only if the relevant live checks were +already reached; it still has false completion and all five flags false. +Historical25-member failure archives remain accepted unchanged with their +original source identities. + +## Verification and publication gates + +Repository contracts construct independently authored inert records under +`/inert/never-executed/` with synthetic IDs/timestamps. Positive records are +explicitly synthetic and establish no native observation. Negative cases cover +exact framing, finite message/history/session/receipt/member authority, +failed/cancelled/active native outcomes, forged success over failed raw, +provider/probe/result/marker/data mismatches and late/forced cleanup. Original +measured archive replay belongs to a separately executed scratch audit, outside +the repository. + +Required before publication: executed focused inert Go and affected Python +contracts, whitespace/gofmt and affected/whole lint gates, original/new reader +scratch replay with unchanged original raw outcomes, and two independent exact +code reviews. Root alone commits/pushes. A fresh genuine current-source hosted +pass plus independent raw audit is required before any tools/call qualification +claim. No release is authorized by this work. + +## Independent code-review corrections + +The first exact implementation19f64f9c0cace7906333f589227f9d711f3b45b5 received +NO-GO from two full independent critics. Its focused Go and86 Python contracts +passed, while actual affected lint reported eight style issues and whole six +lint passed. These receipts do not supersede the review findings or qualify a +native outcome. + +The amended readers explicitly parse the public successful selected add result +and recompute the existing fixed-name physical artifact, client binding and data +receipt IDs. Python now mirrors the Go provider's closed message/content/call/ +function grammar, native research/command/HTTP types and closure, and mandatory +health, pinned metadata, selected skill and shutdown data predicates. Positive +fixtures carry coherent public IDs, selected skill and complete metadata. +Mutation controls update raw receipts and proof digests so semantic refusals +cannot be accidental stale-hash failures. + +Both success readers keep session `current_prompt_id` optional. It is absent at +new session creation; any later present value must equal the one accepted own +prompt. Null and foreign values are refused. Response metadata for the fixed +prompt is absent: pinned `routes/prompts.ts`, blob +e820ef142320ab3349f3bf0b4984c98fb0a847cd, projects only +`origin.clientMetadata?.[0]`; the unchanged fixture request supplies no metadata. +`rest-prompt.ts` blob20cc84b5da623069a3934cc26601cadf2e1b6f5f and the pinned session +schema support these distinctions. No user-origin wrapper or null allowance is +invented. History's already observed user-origin record remains a separate +unchanged predicate. The source files were read and Git-blob/SHA256 verified, +without executing vendor code. + +The exact upstream wire spelling of the canceled terminal reason is preserved +in one documented protocol constant. Human prose/test labels use American +spelling; the original misspell gate is retained. + +Both success readers also enforce the same finite Kimi binding authority. +The thirteen required scalar fields are `client_binding_id`, `client_id`, `scope`, +`target_locator`, `physical_artifact_id`, `materialization`, `activation`, +`authentication`, `policy`, `verification`, `data_receipt_id`, +`native_profile_root` and `updated_at`; each is a string. The only optional +carriers are the observed `package_revision`, `affected_surfaces`, +`native_objects` and `receipts`. Their nested keys and scalar/list/Boolean/integer +types are closed too. The package revision has only tree/manifest digests and an +optional version; native ownership and mutation records admit only the fields +emitted by this Kimi fixture. Other profile, delivery, pending-intent or receipt +authority is refused. This is a finite evidence reader, not another general +domain-state decoder. The native profile is canonical and absolute, with the +exact `.kimi-code` leaf, and joins the canonical project, managed and data paths. +Historical failed archive admission does not invoke this success grammar. + +Python independently caps a successful attempt at180000milliseconds and each +snapshot sequence at2^40, matching Go. Trust and catalog mutability require +actual JSON Booleans; numeric zero/one cannot stand in for false/true. Additional +synthetic controls mutate each of these predicates, including nested binding +types and authority keys, while updating affected HTTP receipts and terminal +proof digests. Original measured9e failures retain all false single-call flags; +none of these source corrections establishes a fresh native observation. + +The corrected `9a642` candidate received a further pair of NO-GOs for success-reader +boundary parity. Python's finite JSON walk now checks every number for finite +float64 conversion and counts keys as UTF8 bytes. Native message IDs require +nonempty, NUL-free text within 256 bytes; workspace IDs and epochs retain Go's +256 byte limit. Native proof message count and probe PID require actual integers, +including refusal of Python Boolean/numeric equality substitutes. Successful +outer command records retain the exact closed shape and require 1..32 nonempty, +NUL-free arguments and a nonempty cwd, each at most 4096 UTF8 bytes. Both readers +refuse NUL in owned inventory paths; the existing 4096 byte key bound remains. +Coherent synthetic controls exercise these findings, including valid byte-limit +cases and a fully joined PID 1 record before a Boolean proof mutation. Historical +failed/component reader bodies, live collectors, commands, protocol, budgets and +authorities remain unchanged. These controls still require exact-source executed +gates and fresh independent CODE reviews before publication. + + +## Final exact-source reviews and measured gates + +The corrected complete candidate569d252624c4088ee20763f7adf732b228f4cc96 received +fresh root and independent Gemini CODE GOs. Its full focused Go and97 Python +contracts passed. The actual affected all-enabled lint then found exactly one +QF1003 in a synthetic metadata control. The author replaced only that if/else +with an equivalent tagged switch; initial user-origin, nil and injection values +and every assertion remain unchanged. + +Final code5d8229b528091963c0496e9bb403d989d83eb73e, tree +d829e0db97f532d8fd6c1afd09dd5d164c891314, has both full-scope approvals with the +exact style delta reviewed: root receipt SHA256 +`d1b99dd8c29e5d0bb2e12fbddc023309bb2a1dd2a31575deabfbc7c23497e9fb` +and independent Gemini receipt +`a6d8000e06cdcbb923f29dea199d2142306f432ad0be66d1af221f8a00ee79fa`. +No implementation changed after this final review. + +Measured final gates use Go1.26.10 and golangci-lint2.13.2: + +- Full selected `^(TestKimi|TestProjectNativeRuntimeValidationContracts)` Go + contracts:38 top-level tests,166 case passes, no skips/failures; package + PASS0.776seconds. Own inert HTTP contracts used loopback permission; no vendor + client, public installer or scanner ran locally. +- Runtime Python40 PASS5.376seconds and Kimi Python57 PASS5.406seconds on569d. + Their entire scripts Git tree is identical in5d822; these97 passes transfer + by that exact identity across the sole Go-test style edit. +- Actual root all-enabled affected lint with + `--new-from-rev=a412ba5e137fdcb7e004393229b323211ed746e1`: zero issues. + Whole unfiltered revive/funlen/gocyclo/gocognit/dupl/depguard: zero issues. +- Independent full original9e and current Python modules re-admit both original + archives identically:25-member single-call failure/allfalse and67-member + component pass/four flags. Original source IDs, archive/member bytes and + outcomes are preserved. The original complete scripts tree was reconstructed + from the exact Git commit; no AST-selected substitute or native execution was + used for this final replay. Receipt SHA256 + `aa0f9362733b7d492a1719f6c0b13c38fbbf8429e7a74f6878d496083004c9eb`. +- Independently authored Python synthetic success passes the Go reader; the + independent Go synthetic success passes Python. The supplementary Go overlay + exists only in scratch and adds no raw capture or fixture to the repository. + Both directions preserve exactly the three MCP success flags. Receipt SHA256 + `40d5e4b5e534b0168ddf832e9b6694d05f11b2cd64dd9c31d6b357a7010bbd1c`. + +Consolidated exact-source gate/review receipt SHA256: +`e69df954b41e4fb53db341ab293f9c22140247106d713cad9cf5c676f2199396`. +Earlier real lint, local socket-capability and disk-exhaustion failures remain +retained; the exhausted link did not execute tests and is never counted PASS. +Only owned regenerable caches and obsolete clean checkout copies were removed, +with source refs and every actual evidence archive preserved. + +This record supports publication for a fresh genuine hosted single-call run. +It is not native completion evidence. The unchanged component lane must retain +its separate four-flag proof; only a new completed native turn with all semantic, +marker/data, original authority and closure checks can qualify three MCP flags +in this lane. Both independent raw reviews are required before a qualification +or merge claim. Authentication, real-model use, releases and deferred VS Code +remain outside this completion. diff --git a/docs/KIMI_PROJECT_NATIVE_HOST_MARKER_HANDOFF_PLAN.md b/docs/KIMI_PROJECT_NATIVE_HOST_MARKER_HANDOFF_PLAN.md new file mode 100644 index 000000000..507b5a715 --- /dev/null +++ b/docs/KIMI_PROJECT_NATIVE_HOST_MARKER_HANDOFF_PLAN.md @@ -0,0 +1,107 @@ +# Kimi single-tool observer: forward only genuine held host markers + +## Actual next failure and source diagnosis + +Current published PR524 head55f5d848fb61899f2c84bd7cccc7592549718b5f, +tree2f20a8e83fe52710eda7ead5494e7821e873ddce, is identical to local +c989277bca17d6205635187fae7a52b349ec3879. Runtime40456546065 call job +122031436268 fails after public installation/receipt proof. Closed native +12712668290 and frontend12712892996 have exact committed source/tree, +bounded canonical unique ordinary ZIP/CRC closure and all five qualification +flags false. Native outer SHA256 +38ceaded9a2b4b9bb28dcfbf6b77bb637012921eef8ea2b7761f6d9e572ec406; +frontend outer SHA256 +3fdc6fc1e63494f32ae666aa7fb933fd094c816f58facee84bbe0e33bba9bd67. + +The actual failure diagnostic (stderr SHA256 +c6a8c370bf0a80ae17a38bcb2e45774944bd4cf9547d8efabb843b688643fbcf) +reports single-tool/host-admission/enter/other, observer_entered=false, +service_recorded=false, cleanup_reported=false and all cleanup values null. +The Python command exits1, stdout0. No nested native API/service was reached. + +Python's unchanged require_hosted in scripts/run-native-client-matrix.py +requires exactly GITHUB_ACTIONS=true, RUNNER_ENVIRONMENT=github-hosted and +AGENTPLUGINS_NATIVE_DISPOSABLE_HOSTED=1, then independently checks actual +platform.system()/platform.machine() against linux-amd64. The Go fixture's +constructor independently checks those same observed markers, actual GOOS/ +GOARCH and ordinary UID/GID before construction. Its closed f.env() intentionally +inherits no ambient host/profile/credential environment, and the single-tool +Python invocation currently uses only f.env(), omitting all three required +host markers. This is a source-proven admission handoff mismatch, not evidence +that the hosted runtime was unavailable or that a native API grammar failed. + +The component observer already forwards the exact three real os.Getenv values +explicitly at its existing Python invocation. Preserve that implementation +unchanged as the established finite reference; its pending native installed +result remains a separate observed gate. Do not speculate about its API failure. + +## Finite handoff after two independent plan GOs + +Scope is repotests/agentplugins_kimi_project_native_attempt_test.go, +repotests/agentplugins_kimi_project_native_attempt_contract_test.go and this +plan. Preserve every previously published external Go/Python change. + +Add a small private single-tool observer environment helper which accepts the +already closed base environment plus exactly three held observed strings: +actions, runner-environment and explicit disposable opt-in. Require their exact +eligible values as validation only; output each key using the held argument, +never a synthesized eligibility literal. Reject the entire request on a missing, +changed, whitespace/control-bearing or otherwise invalid marker. Reject any +duplicate occurrence of these three keys already present in the closed base. +Return a copied environment without mutating the original slice. + +At only the existing private Python single-tool invocation, read exactly the +three named os.Getenv values into this helper, validate those held values and +pass its returned environment to the unchanged command. This revalidates the +same values used in the handoff, so an environment change since construction +cannot silently manufacture eligibility. Keep original HOME/XDG/PATH, profile, +all other closed environment entries and original native working directory. +Do not use os.Environ, bulk maps, credentials, tokens, proxy/provider/loader +settings, guessed runner labels or any broader inherited variables. + +Do not forward a platform override: require_hosted determines the real platform +itself, and the existing outer actual GOOS/GOARCH/UID/GID guards remain unchanged. +Do not alter or bypass either independent hosted guard, set host markers for +local native execution, weaken require_hosted or add fallback credentials. +The Python Context's existing closed vendor-child environment remains unchanged; +this finite metadata handoff applies only to the real Python observer process. + +## Meaningful inert controls and remaining hosted proof + +Add a positive pure helper contract using inert argument values, without setting +the local process's hosted markers or invoking either native guard/client. Assert +the exact closed output contains the original base entries and exactly three +held values, with source slice/capacity unchanged and no aliasing. Negative +controls cover missing/wrong/self-hosted/whitespace/control values for each +marker and duplicate/conflicting base keys; every refusal returns no partial +environment. Plant unrelated ambient credential/proxy/private canaries and +verify none enter the output. Other version/public/native commands must retain +their existing base environment and command tables. + +Run the affected existing Kimi single-tool and new environment contracts, Go1.22 +compatible formatting/whitespace checks and both actual affected all-enabled +and whole-file size/architecture lint only after the shared exclusive Go/lint +slot is granted. No vendor, model, installer, credential session or native guard +is executed/spoofed locally. The existing host-guard negative tests remain. + +Independent code review precedes root-owned publication to existing PR524. +No source pin, runtime request, trust/manual approval, permission, native API/ +provider grammar, identity/receipt proof, budget, supervision/cleanup, generic +failure diagnostic or qualification flag changes. VS Code remains excluded; +no new PR or release. Fresh genuine source-bound hosted output must show the +observer passes its unchanged host admission and reveal the next actual native +boundary. The old failed capture is not relabelled and missing cleanup is not +turned into success. + +## Completed local validation + +Both independent plan and code reviews approved the exact two-file handoff. +On the reviewed bytes, the focused existing single-tool contracts, new pure +environment controls and original closed-environment contract passed (0.012s). +Actual affected all-enabled lint and unfiltered whole-file size/complexity/ +architecture lint each reported zero issues. Formatting and diff whitespace +checks passed. Checks used the granted exclusive slot, pinned Go1.26.10 with +Go1.22 source compatibility, private shared-memory temporary/lint directories, +and the existing bounded module/build caches. No native client, local hosted +guard, installer or model was executed. The genuine hosted follow-up remains +required; the distinct installed component context-stage failure is unchanged. diff --git a/docs/KIMI_PROJECT_NATIVE_OBSERVER_IDENTITY_PARITY_PLAN.md b/docs/KIMI_PROJECT_NATIVE_OBSERVER_IDENTITY_PARITY_PLAN.md new file mode 100644 index 000000000..4d4d407e7 --- /dev/null +++ b/docs/KIMI_PROJECT_NATIVE_OBSERVER_IDENTITY_PARITY_PLAN.md @@ -0,0 +1,114 @@ +# Kimi single-tool observer: preserve supervisory and native identity authority + +## Current source and actual next captured failure + +Published PR524 head b7235fb3a7084a6f1e293676c201dc4fd86f2515 has tree +143c1e9689801aa40e1472fdd6cd1acc68717f9a, identical to local reviewed +b1e8a0a67061dd2390827e1289e5beff9c01c922. Preserve the published genuine +host-marker and nonmutating existing-profile context handoffs, external Go +schema/Windows/context fixes, all Python API/refusal/diagnostic controls and +their complete histories. Fresh b723 results remain a separate pending proof. + +The preceding source705fa429eaad9403113f4fcddb57d3a4f99c96ba, treee8d9fa5d, +genuinely passed the previously failed single-tool hosted admission. Runtime +40459545103/job122042431469 instead failed at service-entry/enter/validation, +observer_entered=false, service_recorded=false and all cleanup values null. +The command exits1/error=false/deadline=false, stdout0. Its exact422-byte +stderr SHA256 is +bec14455aab8b82d644734e45bb62b1b4fe3dd3d48ffd95d81a54d6bd2f1cd5c. +No native API callback or model/tool action was reached. + +Native12715040487 outer SHA256 +d4820f4b3dff5609f3eb8521aa7ef529558d19e3c2e2ca9c8e7d9a50a424a5c5 +and frontend12715030553 outer SHA256 +4b43309441ff4bd894691b2e5e9b5dc65ad299291a8a31fae85fd3bf3db39e24 +have21/25 bounded canonical unique ordinary members and verified CRCs. Exact +source/tree/empty patch list, clean source streams and all24 frontend command +stream byte/hash joins were independently verified; all five qualifications, +vendor-authentication and real-model flags remain false. + +## Source-defined identity roles; no claim about uncaptured owner metadata + +The Go fixture retains and checks all immutable inputs in f.immutable, including +the independently selected Python interpreter and Git executable. Go's held +identity reader admits original-user or root-owned immutable runtime tools. +The private Python service's unchanged shared verify_files instead requires +every supplied identity to be an ordinary file owned by its current runner UID. +Its verification precedes the service/callback, consistent with the observed +boundary. Actual Python/Git owner metadata was not serialized, so the capture +does not identify which exact file or condition caused that refusal. Do not +describe the likely root-managed-tool mismatch as directly captured UID proof. + +The existing component observer already defines the correct role separation: +it copies all immutable entries except the exact f.python and f.git paths into +observerIDs, then adds the selected receipt/native installed identities. Both +tools stay frozen in the original Go fixture before and after the Python +command. Python/Git are supervisory acquisition/invocation inputs; neither is +the native Kimi argv or an installed MCP executable authorized by this private +service. The single-tool observer currently sends its entire f.immutable map, +unlike that component handoff. Align only this role boundary, rather than +weakening Python's owner policy or dropping immutable source/native proof. + +## Finite parity correction after two independent plan GOs + +Scope is repotests/agentplugins_kimi_project_native_attempt_test.go, its existing +attempt_contract_test.go, and this plan. No Python/shared verifier/production/ +component fixture, native argv, environment, runtime request grammar or pin change. + +Add a private copied-map projection taking the held immutable map and the exact +held Python/Git paths. Require both distinct selected paths to exist with held +nonempty digests before returning a result; a missing/ambiguous supervisory +role returns no partial map. Exclude exactly those two complete paths from the +observer-only copy. Do not filter by basename, prefix, owner, mode, executable +kind or arbitrary caller input, and do not exclude any other root-owned file. +Retain each other original key/value unchanged. Keep the helper in the existing +contract/helper file if needed for the unchanged Go file-size gate. + +Use that projection only where the single-tool request currently copies all +f.immutable entries. Then retain the existing protected-file/tree digest merge, +receipt proof and request construction unchanged. Do not remove or modify the +two entries in f.immutable, immutable Go baselines, constructor validation or +f.check before/after the public/native command. The component observer remains +byte-identical as the established reference. Python's current-UID verifier and +all source/native/installed identity checks remain strict. No blanket root-owner +allowance, ownership adoption, extra read or acceptance of a failed service. + +## Meaningful inert controls and remaining genuine proof + +Actual helper contracts use a distinct held map with two selected supervisory +paths, the pinned-client role, source/helper/compiler/scanner roles, and another +ordinary entry sharing a supervisory basename. Require exact output: only the +two exact selected keys are absent and every other held digest is unchanged. +Verify the original map, both selected digests and any separately merged +protected identities remain exact; mutate the returned map to prove no aliasing. +Negatives cover either missing/empty selected role and the same path used for +both roles, with no partial output or input mutation. No local native guard, +vendor binary, ownership spoof or qualification flag is involved. + +Run focused existing single-tool and new identity-projection contracts plus +the existing closed-environment controls under the exclusive Go/lint slot, then +actual affected all-enabled and unfiltered whole-file size/architecture lint, +format/diff checks. Preserve the source-bound failed705 evidence unchanged. +Independent code reviews precede root-only publication to existing PR524 using +a fresh real ref/lease. No release, new PR or deferred VS Code work. + +Fresh genuine source-bound output must show whether the unchanged service +verification and callback now proceed; a later failure still requires its own +measured interpretation. Full lifecycle, restart/removal, MCP protocol/process +and actual cleanup evidence remain required. This exact role projection is +neither a native success claim nor permission to bypass unknown identity errors. + +## Completed local validation + +Both independent plan/code reviews approved the exact two-role copied-map +projection. The native705 inner-member count was independently corrected to21; +its actual failed capture and source/UID inference distinction remain intact. +Focused existing single-tool and closed-environment contracts plus the new +identity role/no-alias/refusal controls passed (0.013s). Actual affected +all-enabled lint and unfiltered whole-file size/complexity/architecture lint +each reported zero issues. Formatting and diff whitespace checks passed. +Validation used the granted exclusive slot, pinned Go1.26.10 with Go1.22 source +compatibility, private shared-memory temporary/lint directories and existing +bounded caches. No vendor, model or positive hosted guard was run locally. +All prior Python/component bytes and full Go immutable guards remain unchanged; +fresh genuine service/callback and full lifecycle evidence are still required. diff --git a/docs/KIMI_PROJECT_NATIVE_PRIVATE_FIXTURE_ROOT_PLAN.md b/docs/KIMI_PROJECT_NATIVE_PRIVATE_FIXTURE_ROOT_PLAN.md new file mode 100644 index 000000000..9d3ab073c --- /dev/null +++ b/docs/KIMI_PROJECT_NATIVE_PRIVATE_FIXTURE_ROOT_PLAN.md @@ -0,0 +1,122 @@ +# Kimi: author the fresh fixture root with its required private mode + +## Fresh source-bound measured refusal + +PR524 head1c0dcd1e9fbd097a97a63c0a8c2e88a17b6dd928/tree +33332edea3af8dd14e67af80c489e22d5a812fe7 preserves the reviewed snapshot +adapter and finite held-directory diagnostic. Genuine runtime40466885261 +passes admission but components job122064401112 and single-tool +job122064401257 both fail at context/enter before Service or any native API +observer enters. Both independently report profile_refusal role=root, +reason=mode, directory=true, mode493 (0755), uid_matches=true and +gid_matches=true; exception_kind=validation. All cleanup fields are null +because no service record exists; all five qualification flags remain false. + +| Capture | Outer SHA256 | Inner SHA256 | Members | +| --- | --- | --- | --- | +| component native12717011752 | 4db6bd87d3988c67f600a2dad4051cc09f40022e10cfa4206016e71bb26181db | 7aa13b6c48f6dec509413db17191996f380092c8fae693eae63bcde3550659c1 | 16 | +| component frontend12717096561 | 72d5dd865572a0c17e3d0c0f3f885f23bee05026bb51924c2676fd45474a7d76 | a6cd5006a321669f5ca7dbdfd2500da1eed2f94e6b425e3f84d38a34508147b7 | 25 | +| single native12716769483 | ad0422ad04b135c08e4a56bfec479d49e1546aa2cac22a023786a9fac8cb0864 | 08143b5ac5862ae06c9c48e1aa63b7b5e13d92b67c7accb3c48f1db60b0ee0bf | 21 | +| single frontend12716908474 | 74cb6eab19bdb59837173fb0f1e072a58d1cd51c9bfff4ea21d9d80a8e5927bb | 35d940b2d441dbeb3dbf66bab51b98390f89d53d219b2d81d65aa12a25e65ec3 | 25 | + +All four archives are exact API-digest matched, bounded canonical unique +ordinary ZIP/CRC checked. Both frontends prove exact1c0/source tree, empty +clean-source streams and all24 command-stream byte/hash joins. Component +stderr538 bytes has SHA256 +ec1f46f3c5b6addb3c828278d711a7bed8abd99bd14af17a132ac42a7cbb81e6; +single stderr545 bytes has SHA256 +13b0a8fad069256f956cd918ab53f31204031fb6eda2d339a56c7fcb603cc379. +Closed raw artifacts and finite audit are retained under +/tmp/uap-shell-fresh-oct27, including kimi-1c-context-audit.json. + +## Existing authoring recipe and exact mismatch + +Both actual Kimi constructors call newNativeFixture(t,false), then configure +their client/project maps and scanner before executing any external Git, +version, public CLI or observer command. The shared constructor calls +t.TempDir(), canonicalizes that freshly owned path and creates HOME, tmp and +four XDG children with0700. It does not set the root leaf's mode. The checked +Go1.26.10 testing source makeTempDir creates its numbered leaf with0777, +subject to process umask, inside a private MkdirTemp parent. Thus the actual +0755 root is consistent with this authoring recipe; it is not evidence of +foreign ownership or a vendor mutation. The Python installed profile helper +requires this root and six named profile directories to be0700, current +UID/GID, ordinary and stable through held no-follow descriptors. Keep that +strict contract. No API grammar or authentication conclusion follows yet. + +## Finite correction after two independent plan reviews + +Scope only the two Kimi Go constructor files, the existing Kimi Go contract +file (private helper and actual filesystem controls), one root-mode refusal +case in the existing Kimi Python contract module, and this plan/validation +record. Do not modify the shared newNativeFixture, another +client, Python validation, source pins, public CLI or production engine. + +Immediately after each Kimi constructor receives its fresh newNativeFixture +result, before assigning client metadata or running any external baseline, +call one private Kimi helper on exactly f.base.Root. This root is newly +created by that constructor inside testing's private parent; no ambient or +user-supplied path is eligible. Existing HOME/tmp/XDG child creation inside +newNativeFixture precedes the call, but no vendor/public/observer action has +run and the private enclosing temporary parent already bounds access. + +The helper rejects a noncanonical/nonabsolute root, any existing ancestor +alias, a leaf alias or non-directory, wrong actual UID/GID, or an initial mode +other than0700/0755. Open the leaf with O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC, +compare its held identity with its initial ordinary Lstat and verify actual +owner/group before mutation. Change only that held fresh root descriptor to +0700. Verify the held descriptor and final ordinary path still name the same +inode and retain expected owner/group/type with exact0700, recheck parent +alias refusal, and check Close. Any error is fatal before external commands. +Never recursively chmod, follow an alias, change a parent/child/foreign path, +adopt an existing user profile or repair modes later during observation. + +All original Python0700/UID/GID/no-follow/stability predicates remain byte +identical, including refusal of a later root0755 mutation. Original genuine +host guards, original HOME/XDG authority, immutable identities, deadlines, +service supervision, private quarantine, source receipts and flags stay +unchanged. No host values are invented and no credentials are inherited. + +## Meaningful verification and publication + +Use actual temporary filesystem paths through this exact helper. An owned +0755 root becomes0700 with identical inode and exact child bytes/modes; a +second call on0700 is idempotent. An ordinary file, leaf alias and ancestor +alias must refuse without altering their modes/targets. Unknown writable +modes must refuse without a change. Existing Python actual-adapter positive and private-directory negatives stay +unchanged. Add an actual root0755 case to the existing Python contract module +that expects the finite root/mode refusal and no filesystem mutation; +no mock hosted guard or vendor executable runs locally. + +Run focused existing/new Kimi inert Go contracts, complete Kimi Python tests, +actual affected all-enabled and unfiltered six-linter gates in the exclusive +slot, gofmt/AST/diff checks, and two independent code reviews. Root alone +publishes reviewed incremental commits to existingPR524 on a fresh ref. +Fresh genuine source-bound evidence must pass the original context/privacy +gate and reveal or complete subsequent actual stages before any runtime or +full lifecycle qualification. No release/newPR or VS Code work. + +## Implemented and recovered validation + +The exact plan received independent root and desktop GOs before code. Complete +implementation review received desktop and CLI GOs on these exact SHA256s: + +- lifecycle: 0b758ace0cac43c9a8b7c3917cb3ddf1a5444f3c5e6dba651bb82985757065cc +- single-tool: 3e885dd5b22afab3f4a69ab305d067eec1bbc53b0fa35764cd72158fa0a8aa9f +- helper/contracts: dd8d61405e489e6dc3050e1172aac4445d5bfc68bbce4464d892cc9046b6e4cd +- Python contract: d14be5f4e940abdc11f6dee1c12d2209b4eb171c47921728415d314d4be62b69 + +After the execution workspace was replaced, all four source files and the +original plan were reconstructed byte-for-byte from the published1c0 source +and reviewed patches; every recorded SHA matched. The raw archives and exact +source/tree/clean command-stream joins were independently restored and checked. +No original unpublished local commit ID is claimed for the recovered history. + +Fresh focused ^TestKimiProject|^TestKimiSingleTool contracts passed in0.176s, +including actual filesystem root-authoring and strict proof controls. The full +57-test Kimi/attempt/service Python suite passed in16.484s. Actual all-enabled +affected lint against recovered plan96ebef5b and the unfiltered whole-file +revive/funlen/gocyclo/gocognit/dupl/depguard gate each reported zero issues. +Gofmt-list, Python AST and whitespace checks pass. No vendor/installer process +or positive hosted guard ran locally. The source-bound1c0 failure remains +failed/all-false; a fresh genuine run of this correction is still mandatory. diff --git a/docs/KIMI_PROJECT_NATIVE_REPEAT_ADD_RESULT_PLAN.md b/docs/KIMI_PROJECT_NATIVE_REPEAT_ADD_RESULT_PLAN.md new file mode 100644 index 000000000..eddd82042 --- /dev/null +++ b/docs/KIMI_PROJECT_NATIVE_REPEAT_ADD_RESULT_PLAN.md @@ -0,0 +1,108 @@ +# Kimi: exact repeated-add result contract + +## Current genuine failure and source + +Use published PR524 source `03d7c243129c98ecdc4cbb99bfe1a47536a556bf`, +tree `de7a5565545f67e26e7e3e101b843f728e3876b1`. Runtime40553154543, +component job122367952819, now passes the installed native observation. +It then fails at repeat-add-a because the fixture's shared array-only +`commandsRequireMutated` cannot read the actual successful direct result. + +Native12759050559 outer SHA256 +`01d59c89fe8124ec17d2ab08f5239e746e23d2c0db7876e34ba482885cef4ffb` +has34 closed ordinary members. Frontend12759450014 outer +`b8163211655fe5215607758975694968dd05bc67c24c3b26a014b599a7ec9aae` +has25. Both archives and CRCs are verified against current API receipts. +The actual repeat-add command exits0, reports success and returns data.result +with mutated=false, no_change=true and the held installation/binding identity. +This failed16.26s capture remains unqualified; later lifecycle stages were not +executed. The separate single-tool approval refusal is a separate slice. + +Production add_multi.go145-154 sends an already installed single target to +runAddLoaded. add.go205 renders the direct newAddResultData on NoChange. +The fixture's first multi-target-style add and later repeated single-target +result are therefore distinct supported public shapes, not fallback aliases. + +## Narrow change and authority + +Change only Kimi's f.uap handling of the exact repeat-add-a/add/project/A stage, +plus one small private helper/contracts Go file and this accepted record. +Keep strict whole JSON parsing and nativeValidateInstallerJSON before the +stage-specific result check. Every other stage keeps the existing shared +commandsRequireMutated array contract. Do not change shared legacy helpers, +production output, command argv/cwd, progress text or installed state. + +The private repeated-add helper requires the already held fixture recipe, +exact stage/add/A/project/want-mutated-false parameters, a direct data.result +object, no data.targets member, data.plugin equal to the held package name, +and exact boolean dry_run=false. Require mutated=false, no_change=true and +requires_confirmation=false with exact bool types. Bind installation_id to +the first independently validated receipt and plan.physical_artifact_id to +that same held native binding. Require the observed plan's client_id=kimi, +scope=project, status=ready, package_mode=native, activation=prepared, +authentication=not_checked, policy=allowed and verification=package_validated. +Require outcome.activation's prepared/not_checked/allowed/installation_verified +facts. No direct/group ambiguity or generic either-shape fallback is accepted. +The existing successful versioned-envelope check and strict JSON duplicate/ +trailing-value checks remain before this branch; require command=add here. + +The existing source, state, native-file, package, data, foreign-tree and +unchanged-operation checks still follow. Neither result metadata nor a new +installation ID may renew the original proof authority. Preserve the four +component qualification gates, the separate initial single-tool false flags, +native admission, original deadlines and the original900s Kimi suite. + +## Meaningful checks and publication + +Use independently stated direct-result fixtures based on the actual public +shape and ordinary inert held identities. Reject array/group and ambiguous +dual shapes, missing fields, wrong types, target/scope/package/installation/ +physical identity, mutated=true, no_change=false, confirmation or dry-run. +Exercise the actual stage-selection seam so every other stage retains the +array-only contract and cannot enter the new repeated-add branch. + +Replay the current held repeat-add stdout against its separately held first +add receipt in a temporary inert Go control, removed before final lint. Do +not commit raw captures or call a vendor/client/installer. Preserve all existing +proof, receipt, mutation, privacy and hostile-schema contracts. + +Obtain root R1 and independent R2 on this exact record before implementation; +the peer clarification requiring physical binding and confirmation checks is +included above. Obtain independent exact-code review. Use the coordinated +Go/lint slot for focused Kimi/shared contracts, affected all-enabled lint, +unchanged whole-file architecture/size lint, gofmt and diff checks. +Keep the code commit separate from any approval diagnostic. Root alone +publishes on a fresh exact PR524 head. A new genuine full component run must +establish later lifecycle outcomes; this correction does not reclassify the +failed archive or qualify MCP calls, authentication, models or a release. + +## Accepted implementation boundary + +Root R1 and independent desktop R2 approved proposal SHA256 +`c709b9d3390263eb602ac1781090b1c0b8f48811c10c0c6696ee8aeff2d38e62`; +the native CLI reviewer independently approved the same plan. Implementation +uses the proof's first held stable installation/physical identities. The new +private selector handles only label repeat-add-a and refuses mismatched scope, +argv or mutation intent; every other label reaches the unchanged shared array +check. No native command has been run locally. Focused inert validation, +actual-stdout replay, lint and exact-code reviews precede root publication. + +Actual inert validation on 2026-10-27: focused +`^(TestKimiProject|TestKimiSingleTool|TestProjectNativeCLI)` passed in 0.392s. +A temporary inert Go control replayed the actual repeat-add stdout against the +separately captured first-add installation/physical identities in 0.009s; +the shared array-only parser still rejects that same direct result. The replay +file was removed before final lint and no raw capture is committed. All +configured linters on affected root lines versus 03d7c243 reported zero issues, +as did the unfiltered six-linter architecture/size gate on the complete root module. Reports +are `/tmp/uap-kimi-repeat-add-affected-lint.json` and +`/tmp/uap-kimi-repeat-add-whole-root-six-lint.json`. The first lint invocation lacked +Go in PATH; a later whole-file invocation accidentally retained all configured +linters and reported unrelated legacy findings. Neither invocation is counted +as the required gates; the successful runs use the exact stated scope. + +Desktop and native CLI reviewers gave independent code GOs. The only review +finding corrected a misleading comment from whole-schema validation to the +actual successful versioned-envelope check. Code semantics are unchanged from +the reviewed tree `ce7d293580faf433844c9b64f6b52456a04b3199`; this validation +record adds no native observations or qualification. Root alone publishes. diff --git a/docs/KIMI_PROJECT_NATIVE_SOURCE_IDENTITY_EXPECTATIONS_PLAN.md b/docs/KIMI_PROJECT_NATIVE_SOURCE_IDENTITY_EXPECTATIONS_PLAN.md new file mode 100644 index 000000000..337fcc3de --- /dev/null +++ b/docs/KIMI_PROJECT_NATIVE_SOURCE_IDENTITY_EXPECTATIONS_PLAN.md @@ -0,0 +1,124 @@ +# Kimi: two exact source-bound observer expectation corrections + +## Baseline and actual observation limits + +Use published PR524 source91a3c54ac74002c0bf67977d3107230f9bbbca30, +tree17957bb4494ad7139a1e5e6fe8a26bbd27f418ce. Preserve its exact private-root +fix and all prior reviewed/external source. New run40493669986 progressed +through context: component job122158328387 completed empty observation and +four public installs, then refused skills-a/validate; single-tool +job122158328503 reached its first provider request and initialize/list events, +then refused approvals/validate before any approved tool call. Both retain +quarantined response bodies, failed/incomplete/all-five-false qualification. + +The four closed archives, API-correlated hashes, exact source/tree/clean +records and48 frontend stream joins are recorded in +`/tmp/uap-shell-fresh-oct27/kimi91a-source-stream-audit.json`, SHA256 +1b68024b3b0a872c9e396bd5c9d1ad1cae34127a39b702215649294a5cfeb970. +Component native12730973797 has31 members, frontend12731208487 has25; +single-tool native12732047373 has23, frontend12732022524 has25. +Do not describe the two source contradictions below as the captured response +values or the conclusively measured causes. They are independently provable +observer defects at the two actual failure boundaries; fresh native evidence +must decide whether another mismatch remains afterward. + +The separate finite-refusal diagnostic plan a8604e9c is available but is not +part of this correction. Do not combine its instrumentation into this slice +or publish duplicate patches while an earlier exact-source run is active. + +## Exact source proof + +All sources below belong to pinned MoonshotAI/kimi-code +b8dd3a134060c6e80ba4a1659335cd63b68483f2. Full files are independently +retrieved and Git-blob/SHA256-verified under +`/tmp/uap-shell-kimi91a-pinned-source`. + +| Source | Git blob | SHA256 | +| --- | --- | --- | +| features/skill/catalog/registry.ts |9d07a1b16b125c4e4b4f07358d34d42437434fc2|265fa39bde3a7a0a58d7772b2769122b58da00316bb4e87bbd39bd91c74762d2| +| app/plugin/manager.ts |f917017e1524964566dc0404f4aafa26fa6b137d|214440d3e0bc69b83f37110878923ff427cff3f898ad5c14ca6999af5e266316| +| agent/loop/turnOps.ts |ec3921a37b4333e8034ccfa0d69380026b819e98|eaa5dcfa8b21784a0c77da2d4e818d34a051a9cfc769e5aa02e4111522847746| +| agent/toolApproval/toolApprovalService.ts |96f36f15ec9fcaf00f4ec373e935004ed14857e2|f1f79066f2184a112774fb1f025cb25580f991f4a9c14aa73104a0cfc439036d| + +Paths in this table are relative to packages/agent-core-v2/src. +`PluginManager.pluginSkillRoots()` uses source extra and a held plugin.id. +`InMemorySkillCatalog.registerPluginSkill()` stores the bare plugin skill +separately and stores the public listSkills row with exact name +`${plugin.id}:${bareName}`. The workspace route builds that catalog and calls +listSkills/toProtocolSkill; its blobde5525e6/SHA +9f820a2cb91eef9a1a24a0fb439fece7da9da9c6bdd956045b16b57c32ba31ec +was also verified. Current UAP user activation registers the installed plugin +at original HOME/.kimi-code/plugins/installed.json; it does not copy that +plugin skill into project/.kimi-code/skills. The independently authored user +plugin ID and bare skill name are both uap-kimi-native-user. Therefore the +expected native user row name is exactly +uap-kimi-native-user:uap-kimi-native-user, source extra and the same owned +SKILL.md path/digest/description. Current observer expects its bare package +name. Project direct skill names remain exactly bare a/b/c names. + +`turnOps` initializes nextTurnId=0 and assigns the first TurnPrompt its +current nextTurnId, then advances it. The single-tool observer creates a +fresh session, verifies message_count/last_seq, then submits one prompt. +Approval service carries context.turnId into interaction tags; pinned +kap-server approval route b90f1023 maps that numeric tag to turn_id. Current +observer requires turn_id>=1, contradicting this fresh first-turn identity. +Require exactly integer0 for this selected first-turn approval, rather than +accepting an arbitrary nonnegative or later turn. Bool is not an integer. + +## Finite source delta + +1. In the component Go observer request authoring only, construct the expected + native skill name from the already held fixture scope/package identity: + exact user role maps to pluginID:bareName; a/b/c remain unchanged. Keep + package/manifest/registry/NativeObject/file-frontmatter names, source extra, + description/path/digest and all public/receipt authority unchanged. Do not + rename installed files or normalize an incoming native name. A small pure + private helper must reject unknown/mismatched fixture role/name inputs. +2. In the existing Python single-approval validator only, require the exact + fresh first turn integer0. Preserve the same current session/main agent, + provider-owned call ID/tool/arguments/action/display/approval-ID/timestamp + checks and ordering. Missing, bool, string, negative, positive/later turn, + duplicate/unknown field and all current permission negatives still fail. + Preserve ResponseSchemaRefusal separately and the graceful initial-capture + branch; no additional approval, retry, request or remembered scope. + +Scope: one existing Go component lifecycle request-authoring file, one bounded +new private Go expectation helper/contracts file if needed, existing Python +attempt validator/tests and component collector tests, and this plan/validation +record. No production adapter, installed source, shared process/host guard, +context/environment, native pin, provider behavior, diagnostics, cleanup, +deadline, archive admission or qualification change. Keep source history of +the two corrections separable in local commits even if root publishes them +together after final review to avoid unnecessary duplicate native runs. + +## Required meaningful verification + +Go contracts must use the actual authoring seam with real held user/project +proof fixtures to show that only expected native user name differs; selected +path/digest/description/source remain the existing exact receipt authority, +all four scopes reject malformed roles/names, and no passed receipt/name is +adopted as a new package or native path. Python installed-skills contracts +must accept exact source-shaped qualified user+A/B/C rows and reject bare +user, foreign plugin prefix, wrong scope, duplicated/missing/project sibling, +wrong path/description/source and malformed fields. Keep the generic catalog +grammar strict; only the expected held request name changes. + +Single-tool contracts must use actual session/prompt/approval observer seam: +source-shaped first turn0 reaches the existing one-call approval and ordinary +shutdown path; every wrong turn class/value remains a refusal before that +action. Correct the old inert service's fabricated turn1 to source-derived0 +so existing session/permission/schema/privacy cases remain meaningful, not +masked by the stronger first-turn equality. Explicitly retain wrong tool/ +session/agent/provider call/action/display/args and unknown-key controls, +ResponseSchemaRefusal behavior, no-call-before-approval events and no blanket +scope in the outgoing approved request. No native/vendor runs locally. + +Obtain two independent plan GOs before code and two exact-code reviews after. +Run affected existing/new Kimi Go contracts plus the complete Kimi/supervisor +Python suite, formatting/AST/diff and affected/whole-file lint in the granted +exclusive Go slot. Root alone publishes the frozen plan/code on fresh PR524 +head. Both installed lanes then need new genuine source-bound raw proof; +single-tool native-history capture remains deliberately unqualified even if +the provider/probe exchange advances. Any next grammar/permission discrepancy +needs a separate evidence-backed plan; neither source correction qualifies +authentication, model service or a previously failed artifact. diff --git a/docs/KIMI_PROJECT_NATIVE_SOURCE_IDENTITY_EXPECTATIONS_VALIDATION.md b/docs/KIMI_PROJECT_NATIVE_SOURCE_IDENTITY_EXPECTATIONS_VALIDATION.md new file mode 100644 index 000000000..591566887 --- /dev/null +++ b/docs/KIMI_PROJECT_NATIVE_SOURCE_IDENTITY_EXPECTATIONS_VALIDATION.md @@ -0,0 +1,52 @@ +# Kimi source identity expectation checks + +The approved plan is `KIMI_PROJECT_NATIVE_SOURCE_IDENTITY_EXPECTATIONS_PLAN.md`, +SHA256 `0248a4f6a26077468b1b2c7f6ece24898c932d784d0c0909ed485d00709d95be`. +CLI and desktop independently reviewed the complete plan and full pinned native +sources before code. Both also gave independent exact-code GOs on the same +five source hashes below. Their conditional actual-check requirements are now +closed. Root remains the only external publisher. + +Local plan commit a4aa9f5c is followed by two separate corrections: +93758271 authors only the exact expected plugin-qualified user skill name; +c73a696e requires the exact fresh first-turn integer0. Their code tree is +`4d9e6e76d1bdc6f25c9f7ba2cc8ee3babd13044d`. + +| Exact source | SHA256 | +| --- | --- | +| repotests/agentplugins_kimi_project_native_lifecycle_test.go |74540783f24afc434f7851bc147e4122f6e841f08133530610c5ffdbefafa9b1| +| repotests/agentplugins_kimi_project_native_skill_name_test.go |5469b6b4d7d7c0aead27924d347eb0dfe668016e8331ad96472097c6fb5a9bfa| +| scripts/test_project_native_kimi.py |976c85ac1817c2bd0d869c4eaf7f55443c0d6324d6d5c44fb48eccf63093ebb4| +| scripts/project_native_collectors/kimi_attempt.py |bd49f1777c44bf39aca68c1f391e422ddbe4bcf3a21f6c6ed77dc8cb0e6c365a| +| scripts/test_project_native_kimi_attempt.py |eaae849851de8415ea1bc5db0f348df3d63d22761ef3a0ed65f55440765f2f9a| + +Actual offline checks on those final bytes, 2026-10-27: + +- Focused Go `^TestKimiProject|^TestKimiSingleTool`: PASS0.255s, including all + four actual Loader/Planner/Stager/adapter/proof user/A/B/C request-expectation + contracts. These execute inert owned files, not a Kimi/native installer. +- All configured enabled linters on affected lines from plan a4aa9f5c: + zero issues. +- Unfiltered whole-file revive/funlen/gocyclo/gocognit/dupl/depguard on the + complete repotests package: zero total issues, not merely zero selected-file + issues. Report `/tmp/uap-shell-kimi-expectations-whole.json`. +- Complete Kimi collector, single-tool and shared supervisor Python suite: + 59 tests PASS17.884s. The actual observer seam accepts firstturn0, sends + exactly one selected decision with no remembered scope, and keeps native + capture/history unqualified; laterturn1 stops before that action and raw + HTTP remains quarantined. Existing schema/identity/privacy controls pass. +- Python AST, gofmt and git diff checks are clean. + +Go1.26.10 and golangci-lint2.13.2 used the recovered official exact assets, +GOPROXY/GOSUMDB off, approved private shared-memory caches, GOMAXPROCS2, +GOFLAGS -p=1 and GOMEMLIMIT500MiB, in the explicitly coordinated exclusive +slot. The slot was released after checks; no process remains. + +Current hosted source91a remains failed in both installed lanes at the +observed skills-a/approval validation boundaries. Its response values were +quarantined, so these corrections remain source-proven observer fixes, not +assertions about uncaptured response bodies. Fresh genuine hosted component +and single-tool runs are mandatory after publication. The single-tool native +history review gate and all account/model qualification limits remain intact. +The alternative finite-refusal diagnostic plan is retained outside the code +checkout and is not implemented or included in this candidate. diff --git a/docs/PROJECT_INSTALL_OWNER_SCOPE.md b/docs/PROJECT_INSTALL_OWNER_SCOPE.md index 633598c32..81ed00f03 100644 --- a/docs/PROJECT_INSTALL_OWNER_SCOPE.md +++ b/docs/PROJECT_INSTALL_OWNER_SCOPE.md @@ -1,5 +1,21 @@ # Project installation: owner scope clarification +## Owner reprioritization, 2026-10-27 + +The owner explicitly deferred VS Code: it is not a priority and is skipped in +this continuation. Complete the nine remaining client leaves in PR521-529 and +their applicable end-to-end verification, independent review and merge gates. +Keep PR530 as a deferred draft; preserve its existing source, recorded evidence +and unpublished work. Do not run new VS Code qualification, change its dedicated +implementation or merge that leaf as part of this continuation. Its incomplete +qualification does not block the active nine-client program. Preserve existing +baseline regression coverage for previously supported behavior. + +This latest scope decision supersedes earlier instructions below that require +VS Code follow-through or count it among the active remaining targets. It does +not change the evidence requirements for any active client, promote a blocked +native case to passed, or authorize a release. + Accepted owner instruction, 2026-10-23. This document records the scope of the current project-installation program; it does not change release availability. diff --git a/docs/plans/project-install-e2e/cline-absent-owned-skill-plan.md b/docs/plans/project-install-e2e/cline-absent-owned-skill-plan.md new file mode 100644 index 000000000..fd6614651 --- /dev/null +++ b/docs/plans/project-install-e2e/cline-absent-owned-skill-plan.md @@ -0,0 +1,110 @@ +# Cline: inject absence of the exact owned skill directory + +## Actual closed boundary and independent product contract + +The first complete-cycle source6dedead8637b5f1eed766c8797b38bb0037e147b, +tree4e7e060171effdc34099cf2e9c20b22c0e474827, genuinely ran in +40467050469/native122065612975. Its API-hash-matched frontend12718201141 +(outer226fe05c9c7459e10b31d03cf7b9b2972ed7ca698de7a83de692a3c4f549018d, +inner4a268b067e721ebe250238ecd4c9087fa833dfdf2273eb4c0dc125324f4ad392) +contains31 closed ordinary canonical members and all30 command-stream joins. +The exact selected test failed at missing-repair-a after53.22 seconds. +The native archive was quarantined with ValueError, so the public repair's +actual stdout/stderr/exit and native empty-mode raw frames remain unavailable. +Do not claim those facts or relabel that first run. The separate reviewed +complete-JSON privacy correction must remain preserved and pass final gates. + +Read-only source establishes a fixture mismatch independently of hidden stderr. +The current missingA removes only r.SkillPath (SKILL.md), leaving the selected +owned directory present. The Cline project adapter uses shared.ProjectComponents +(project_lifecycle.go), whose verifyComponentSkill (project_components.go161–178) +permits allowMissing only when Lstat of the exact NativeObjectOwnership.Path +returns absence. A present empty directory receives a valid different digest +from shared.DigestSkillDirectory and remains a correctly refused altered object. +The current NativeObject Path is the independently computed skill directory, +not its SKILL.md leaf. Existing Codex/OpenCode missing-repair E2E cases remove +their exact owned directory. This plan aligns the injected absence with that +existing ownership unit; it does not authorize repairing partial tampering. + +## Narrow test-only amendment after two independent plan GOs + +Change only repotests/agentplugins_cline_cycle_lifecycle_test.go and the existing +agentplugins_cline_cycle_stager_contract_test.go, plus this new plan/validation +record. Do not rewrite approved lifecycle or privacy plan history. Preserve +all15 public commands/14 listing stages/10 ACP stages/54-member maximum, +source pin, original150/180 budgets, process supervisor, source recipes, +receipt identities, data/foreign/sibling guards and first-capture fatal/allfalse. +No product, client adapter, protocol, Python admission or expectation widening. + +The fault remains selected only after complete independent recipe/state/native +ownership/projection/data/foreign proofs and f.check succeed. Require exact +project-a owned skill NativeObject kind/name/path/source/digest from the prior +proved binding and independently expected filepath.Dir(r.SkillPath). Retain +the existing held ordinary single-link SKILL.md read. Suspend only that selected +leaf's protected digest and its selected skill-root inventory, as before. +Then perform two checked nonrecursive removals: os.Remove(r.SkillPath), followed +by os.Remove(the exact owned directory). No RemoveAll, tree walk deletion, +ancestor removal, sibling adoption or receipt/state/config/data deletion. +Any unexpected additional entry causes the directory removal to fail. Require +Lstat exact owned directory to return os.IsNotExist afterward, and f.check +still proves all remaining protected/source/data/foreign/sibling authority. + +The existing subsequent public missing-repair-a command and all its strict +exit/progress/JSON/independent receipt proofs remain unchanged. Fresh listing +and ACP must still observe exact restored a-two bytes/authority before removal. +Actual public repair success remains a fresh genuine hosted observation. + +## Meaningful real file/adapter controls + +Reuse clineCycleInert and clineCycleStageActual (real Loader/Planner/Stager, +Store and adapter file activation; no executable invocation). Allow the latter +test helper to return its exact existing domain.ActivationRequest, preserving +its current call/activation behavior and existing callers, so new controls can +reuse the same real plan/delivery rather than synthesize observed authority. + +Positive: stage actual project-a, preserve its complete state/config/managed +package/data/foreign bytes and metadata, run the actual missingA fault helper, +and assert the independently expected NativeObject directory itself is absent. +Reapply through the real cline.Adapter.Activate with the exact prior native +objects and original active delivery (Replacing=true), without any process. +Require Installed/Prepared, exact restored source-bound skill bytes/digest, +unchanged state/receipts/data/config/foreign trees, then run the existing full +independent proof. This validates the file mutation boundary; it does not +fabricate a public CLI or native-session success. + +Negative: on a separate actual stage, remove only SKILL.md while leaving the +owned directory. The exact real adapter replacement must still refuse and +preserve that altered directory, managed package/config/state/data/foreign +bytes and metadata. An extra unrelated file must also remain refused and +unmodified. Assert no native success/receipt renewal and no adopted baseline. +These controls prevent the fixture correction from hiding tampering-policy +regressions. Preserve all original hostiles, exact repeat-remove refusal and +independent source/current-schema contracts. + +Run focused existing/new ^TestClineCycle and ^TestClineProject inert contracts, +affected all-enabled lint and unchanged whole-file gates only in the exclusive +slot after final numeric correction gates. Obtain two independent complete code +reviews and exact manifest/tree checks. No local installer/vendor executable +or positive hosted guard. Root alone may publish reviewed commits to existing +PR525 with a fresh non-forced head lease. Review the next actual source-bound +native archive, including empty-mode grammar, remaining repair/removal/restart +and user/A/B/MCP authority before any separate qualification amendment. +No new PR, release, VS work or qualification promotion. + +## Actual candidate validation + +Desktop and shell independently approved both the exact original plan +SHA2561d62e737d8475e768b1ff90c8c0f635c246714fd70dbd508e26320ab95838d79 +and complete two-file implementation. The final lifecycle file remains +SHA2561fa1b8ee4cd45268ad6f5da251b42665d72fb15288e360e53b38459fc20c6e96; +the actual Stager/adapter contract file remains +SHA2568016b74c507052af60a8c7acb83cc572485518790023d4fd000bef7fc88231b1. +With the separately validated numeric privacy correction preserved, offline +focused Cline cycle/project contracts passed in0.171s. The real adapter +restored the exact absent owned directory; partial-leaf and extra-file +tampering still failed without adoption or mutation. Checked-in all-enabled +affected-line lint and unfiltered six-linter whole-file gates each reported +0issues; gofmt and diff checks are clean. No vendor, installer or positive +hosted guard ran locally. The public repair result and complete fresh native +cycle remain future source-bound observations; all qualification gates and +the intentional first-complete-capture failure remain unchanged. diff --git a/docs/plans/project-install-e2e/cline-complete-cycle-qualification-plan.md b/docs/plans/project-install-e2e/cline-complete-cycle-qualification-plan.md new file mode 100644 index 000000000..358ba67dd --- /dev/null +++ b/docs/plans/project-install-e2e/cline-complete-cycle-qualification-plan.md @@ -0,0 +1,219 @@ +# Cline measured complete-cycle qualification amendment + +## Frozen genuine evidence and remaining gate + +This is a separate amendment after, rather than a reclassification of, the +first complete hosted capture. Existing PR525 head +`e5ec161d1ebe4e81f62a87a62ce2c39647bee17b`, tree +`f1d738deeb8ea2eee11e7b67490135ebb96daf21`, ran genuine pinned Cline3.0.73 +in workflow40493640907/native122157001818. The selected test reached every +required stage in82.87s and failed only at the deliberately installed final +raw-review fatal. It remains failed, runtime-incomplete, and all five +qualification/authentication/real-model flags remain false. + +Native artifact12730862939:112206 bytes, outer SHA256 +`327aff9e24dfcdd2b3edb0a0614be4f138a002079e99176d818d03c9bce699f6`, +inner `583e060cb1e0ae406ac8bc029224dd5a7b1ebce062ff432285868572a7c9a218`, +54 ordinary canonical unique CRC-checked members. Frontend12731182543:22981 +bytes, outer `7bf9d2f86ea3b1afaf1b8f1b124c5dc5fc442e630efbc3d1a36c4b06fd799d5d`, +inner `3781de4617e3acdde069168e786de6d1b306584f8bf2427594a21ad4e51c7cd7`, +31 members. Fresh API receipts match source, sizes and hashes. Independent +audits close30 frontend streams and130 decoded aggregate byte/hash joins, +15 public commands,28 listing selections,18 source/state proofs and10 ACP +sessions. CLI audit report SHA256 +`4442577295bd1d067df83f3f9e21bc79f21cf95e289f7642eb1a15bf59b37abb`; +shell independent report +`f96d94754bccc7acbb547616450764eb3be74cb8c96b9b6dd57784334431bb5d`. +These are evidence references, not runtime hash exceptions or an allowlist. + +The raw receipts independently bind three distinct/stable installation, +physical/client/data identities; A-one to A-two update and exact repair; +original user/sibling selection; the exact natural repeated-remove refusal; +source-bound roots/data/argv/revision; fresh native/probe sessions and event +intervals; and ordinary provider/delegated cleanup. The live source also +verified complete source/config/payload/foreign/data/marker byte and metadata +trees before and after operations. Those unexported bodies are source-attested +live checks, not independently recreated raw captures. Account authentication +and real-model service were not exercised and cannot be qualified here. + +## Measured native grammar + +The existing strict owned parser already matches all five new owned +transcripts: initialize result(id1), new session(id2), pending tool update, +one exact permission request, in_progress update, pending tool_call, +completed update with exact MCP result, exact sentinel text, one timestamped +session_info_update, then prompt result(id3/end_turn). Agent identity is +exactly cline/3.0.73. Exact allow_once only, explicit auto_approve=false, +empty injected MCP servers, session/call identity and existing unknown, +duplicate, tool failure, ordering and cancellation refusals remain unchanged. + +All five actual empty transcripts have exactly five frames: initialize, +new-session, exact sentinel text, one session_info_update, prompt end_turn. +They declare no owned MCP tool in the one provider request, request no +permission, emit no owned tool event or probe event, and never approve a tool. +The raw empty-a transcript is2311 bytes, SHA256 +`4fb51da519e6c13c7d111397219bf25e87475942995aedf3a837785f5dfeaa2a`. +This observed shape confirms the existing finite empty parser; no new event, +field, tool capability, authentication or native command is accepted. + +| ACP stage | Operation | Frames / HTTP / permission / probe events | +| --- | --- | --- | +| empty-a | empty |5 /1 /0 /0 | +| empty-b | empty |5 /1 /0 /0 | +| installed-a | A-one write |10 /2 /1 /3 | +| installed-b | B-one write |10 /2 /1 /3 | +| updated-a | A-two read |10 /2 /1 /3 | +| repaired-a | A-two read |10 /2 /1 /3 | +| removed-a | empty, A data retained |5 /1 /0 /0 | +| remaining-b | B-one read |10 /2 /1 /3 | +| final-a | empty, A data retained |5 /1 /0 /0 | +| final-b | empty, B data retained |5 /1 /0 /0 | + +## Narrow source change and finalization + +Preserve the exact complete public/listing/ACP/proof matrices and all existing +live authority and failure checks. Change the newly emitted cycle mode from +`cline-complete-cycle-first-capture` to `cline-complete-cycle`, with +cycle_capture_review_required=false. At the end of the actual test replace +only the deliberate review fatal with recording cycle_observed_complete=true +and attempt_stage=complete-cycle. This does not itself qualify anything. + +The deferred complete-cycle owner must still close the original provider, +wait for all handlers/serve, reject forced cleanup, freeze all8 aggregates, +validate the exact final matrices and complete cleanup tuple, perform final +live protected/absence/tree checks and private-canary scans, and honor the +original total deadline. The existing f.finish must decide the final result +only after its provider/total checks. A small cycle-only finalization helper +will set runtime_attempt_complete=true and all5 qualification flags true +only when no testing failure exists, the new mode/review marker is exact, +cycle_observed_complete is true, all fixed stages are complete, and provider +cleanup is ordinary and complete. Missing/wrong/partial receipts refuse. +Any failure before that point explicitly resets completion and every cycle +qualification flag false; no stale success survives a late cleanup/deadline +failure. Legacy single-attempt behavior remains unchanged. + +The five qualified IDs, if a fresh run passes, are project-lifecycle, +native-restart-removal, mcp-initialize, mcp-tools-list and mcp-tools-call. +Activation remains prepared: native discovery is through the supported +explicit process-wide CLINE_MCP_SETTINGS_PATH, not cwd autodiscovery or +global activation. vendor_authentication_qualified and real_model_qualified +remain false unconditionally. + +The unchanged outer frontend must still require a selected executed passing +Go test, ordinary closed delegated cgroup with no forced stop/kill, immutable +source/runtime files, successful strict native admission, and complete +collection before copying any qualification into its result. Archive-writing +or outer-service errors therefore cannot turn a failed workflow positive. +Do not relax the frontend selected-test/service/cleanup contract. + +## Admission and retrospective preservation + +Retain the old first-capture mode and its failed/allfalse-only admission, +including partial failure prefixes. Do not rewrite the e5 artifact/summary +or change it to qualified. Route the new complete-cycle mode separately. +For that mode allow only the paired results: failed/incomplete/all5false, +or passed/complete/all5true. Reject mixed booleans, nonbools, partial +qualification and authentication/model promotion. Success requires exact54 +members,15 public triples,14 listing pairs,18 proof records,10 native/command/ +probe/provider receipts, exact clean public outcomes including repeat-remove, +exact closed successful provider tuple and source identity; no prefix may +qualify. Keep all current byte/hash/private/resource/ordering/type checks. + +For new success only, add a bounded client-specific semantic join helper +over the already decoded streams. Require the measured5/10 ACP sequences, +exact agent/version/new session/end_turn/sentinel, empty absence, owned +pending/permission/in_progress/tool_call/completed identities, the exact +three-option permission list with only an allow_once response, provider +tool-call ID/arguments/result, identical native +result/probe facts, initialize/list/call order and timestamps in each native +interval, fresh native/probe IDs, and the selected proof's source revision, +package/data roots/argv/marker. State streams must be current-schema5 single +installations with exact source-recipe references and stable separate +user/A/B installation/client/data receipt authority; active user skill-only +still has blank token and zero receipts, retained removals have no clients. +Success must not admit the existing deliberately inert capture-only fixture +merely by changing its summary flags. This helper validates the qualification +envelope; the existing live Go checks remain authoritative for uncaptured +filesystem identity and complete-tree preservation. + +The ACP aggregate captures native stdout only. Its exact inbound permission +options/identity join the provider's single_call_approved receipt; the outgoing +allow_once response itself is attested by the unchanged exact Go writer +(agentplugins_cline_project_native_provider_test.go, current line584), not +retained as a raw outbound stream. Do not invent such a stream or add a new +capture field. Actual offline parser replay must independently assert the +outgoing buffer contains the exact one allow_once response and no extra +permission authority; the new Python helper verifies the inbound/approved +receipt join and explicitly relies on source for that outgoing writer. + +## Scope and meaningful verification + +Source scope: existing cycle fixture/lifecycle and native attempt Go test +files; a small new cycle-completion Go helper/contracts file; existing +project_native_runtime.py and its inert test module; one bounded new +client-specific Python success-join helper/contracts module if needed to +keep the existing files within architectural/complexity limits; and this +concise plan/validation record. No product adapter, shared process/host, +acquisition/pin, workflow, runtime environment, provider protocol, portable +manifest, legacy tests, trust policy or VS Code changes. Do not commit raw +per-command captures; retain e5 artifacts as the measured replay source. + +Inert Go contracts must test actual empty/owned replay and unchanged outgoing +authority, as well as the finalization function's full success and late +failure/deadline/cleanup/missing-stage/type/mode combinations. Preserve all +existing empty/permission/source/data/tamper/privacy hostile controls. +Python contracts must preserve failed first-capture admission and prove +new success requires its exact full semantic closure. Exercise all missing +members/stages, permission/probe in empty stages, altered call/session/result, +source/revision/data-root confusion, cleanup failure, mixed/partial flags and +source mismatch. Use actual e5 raw offline for a temporary replay of all10 +native transcripts and the new semantic admission helper; changing only +the summary in that inert test is explicitly synthetic protocol validation, +never retrospective runtime qualification. Remove temporary repo replay +files before final lint/commit. No local vendor execution. + +After two independent plan GOs, implement, obtain independent full code +reviews, then use the exclusive shared Go/lint slot for focused Cline/shared +contracts, affected all-enabled lint, unfiltered existing size/architecture +lint, and affected Python tests. Freeze exact source hashes/tree and validation. +Root alone publishes on the existing PR525 with a fresh exact-head lease. +Then a fresh genuine hosted full cycle must pass and its exact source-bound +closed raw/frontend/cleanup evidence must be independently audited before +merge or program completion. The reviewed e5 capture remains historical +failed evidence and cannot substitute for that fresh success. No release. + +## Exact local implementation validation (2026-10-27) + +Independent desktop R1 and shell R2 approved the full plan SHA256 +`9bde3ef5800a9b0d0562945d200bc443fd040257ad1527314e2ff17b5bb17734` +before implementation. Both then reviewed the complete eight-file code delta +and approved final code tree `b32aeac3cf9c883887cd7dfefee7e3787535c3a5`, +local code commit `3f9b270f05bb998f5ece14268e167a4ab07bea86`, manifest SHA256 +`35e179ac78ff579bc650adbd7d810467780cedba14eb9ea3e5ca522ac955cf73`. +Review findings were resolved with consistent rehashed raw negatives: reject +extra provider response/history calls; bind exact native object IDs, logical +and source-relative names plus source-frozen skill digests; enforce measured +modes/models and fully typed config options; reject a fifth duplicate option +before mapping. Original live ownership, ordinary cleanup and budgets remain. + +Actual inert focused Cline/shared Go contracts passed in0.293s, including all +ten genuine e5 ACP transcript replays. Replay independently checked the exact +outgoing buffer: five owned stages had one sole allow_once response, five +empty stages had none, and every new session had empty injected MCP servers. +The temporary replay test was removed before both lint gates. Canonical +Go1.26.10 and golangci-lint2.13.2 with the checked-in configuration returned +zero affected all-enabled issues and zero unfiltered six-linter whole-file +size/architecture issues; no custom exclusion/configuration was introduced. +The four reviewed Go source files stayed byte-identical through those gates. + +The existing runtime workflow's exact Python selection also loads the new +semantic contracts: final27 tests passed in7.078s, covering complete authored +semantics, every missing member, partial flags and rehashed raw hostiles. +The complete genuine e5 raw archive still admits as failed/allfalse unchanged. +A separate in-memory synthetic new-mode summary over those same raw bodies +passes the new semantic joins; it validates parser compatibility only and +does not reclassify that historical capture. Formatting, Python AST and diff +checks passed. No local vendor process, account or real model was used. + +Publication and the required fresh genuine successful full-cycle audit remain +root-owned follow-through; these local checks do not claim they occurred. diff --git a/docs/plans/project-install-e2e/cline-complete-json-privacy-recovery-plan.md b/docs/plans/project-install-e2e/cline-complete-json-privacy-recovery-plan.md new file mode 100644 index 000000000..83b77063f --- /dev/null +++ b/docs/plans/project-install-e2e/cline-complete-json-privacy-recovery-plan.md @@ -0,0 +1,101 @@ +# Cline: recover the approved complete-JSON privacy correction + +## Measured false refusal and preserved plan authority + +The independently audited successful single installed-tool capture at source +9d01aefb71f572d69dbe5d36c507b235d19c8059 has 21 closed native members. +Applying the later cycle privacy scanner to every retained raw body refused +only its 75391-byte runtime-attempt.json. The finite reason was an eager +nonfinite numeric conversion in an ordinary 64-byte metadata string, before +the parser established whether the whole string was complete JSON. No depth, +node or text-work bound was exhausted. A source-independent reproducer is +the 64-byte string consisting of "1e999" plus 59 "a" bytes. + +Root, desktop and shell approved the original shared correction plan with +SHA256 a8480f5657ce93e04d72d7cda7232ad85d79b87a5afbe908f3e57d3561ccd319. +Its local plan and final candidate were unpublished when the execution scratch +was replaced. This recovery record does not claim to reproduce that plan's +exact document bytes or the lost candidate tree. The published complete-cycle +plan and source6dedead8637b5f1eed766c8797b38bb0037e147b, tree +4e7e060171effdc34099cf2e9c20b22c0e474827, were recovered from public Git +and independently verified unchanged. + +The recovered Go privacy helper is byte-for-byte the previously approved +SHA256266b343cd1c6809b4bd302620e5b1345dc6f33af55e8988abe7fac974441db38. +The three remaining equivalent source/test files have new hashes and received +fresh complete independent code reviews from desktop and shell. No old final +tree or test pass is attributed to these new bytes. + +## Exact finite correction + +Change only the existing Cline cycle privacy helper/contracts and the existing +Python runtime admission module/contracts. Only the strict parser's static +nonfinite-number refusal invokes an extra complete-document syntax check. +Charge that attempt to the same whole-member four-times-byte budget. +No per-string or per-line budget renewal is allowed. + +The Go syntax preflight decodes into json.RawMessage and performs a second +RawMessage decode requiring exact EOF. Neither step evaluates floating-point +numbers. Do not use Token for the second decode: incomplete framing such as +"1e999 1e999" must remain ordinary non-JSON text. Python uses numeric +placeholders for this syntax-only decision and explicitly rejects nonstandard +NaN/Infinity constants as valid JSON syntax; it does not add a protocol parser. + +Complete nonfinite JSON remains refused. Ordinary incomplete numeric-prefix +text falls through to the existing literal canary and every subsequent valid +JSONL record. Structural/duplicate/UTF8/depth/node/resource ambiguity remains +conservatively refused. The shared budgets, recursive key/value/string scans, +before-base64 inspection and all other existing canary controls are retained. +No hash allowlist, prefix regex, protocol acceptance or private-data export is +introduced. + +Preserve all installer/native source pins, exact owner/data/profile authority, +public command/listing/ACP matrices, actual process supervisor and original +150/180-second budgets. The first complete cycle remains intentionally failed +and unqualified until fresh raw review and a separate reviewed completion +amendment. No native/authentication/model or lifecycle qualification is promoted. + +## Verification and publication boundaries + +Independent controls cover 64-byte ordinary text, nested keys/values/lists, +valid JSONL, complete nonfinite numbers, two-value incomplete framing, +nonstandard constants, a later encoded canary after an invalid numeric-prefix +line, exact shared byte debit and deep syntax-resource refusal. Existing +duplicate/nested-string/private/UTF8/structure controls remain unchanged. + +Run the focused Cline cycle/project inert contracts, complete Python runtime +contracts, actual retained raw-body replay where the artifact is reacquired, +all-enabled affected-line lint and the unchanged unfiltered six-linter gate. +The scratch replacement invalidated access to former caches and evidence; +restore official pinned tooling and API-hash-matched artifacts before a new +claim. Never label ENOSPC or missing evidence as a passed check. + +Root alone publishes reviewed commits to existing PR525 on a fresh non-forced +ref. A new genuine hosted cycle is required to expose the still-unobserved +missing-repair command details and remaining removal/restart facts. No vendor +client or hosted eligibility spoof runs locally. No release, new PR or VS work. + +## Actual recovered-candidate validation + +Fresh complete four-file reviews from desktop and shell approved manifest +473da3d495e598c2d11ee2c640e29c1ca9cca12f69086e6c328db2b7ca68d91f. +The exact restored official Go1.26.10 binary SHA256 is +9c2a37ae5b21ba1d5a004bb9ab4d0c64de6fc5778e9d30487adccea62678b8b5; +golangci-lint2.13.2 binary SHA256 is +97aa6134a250a0f964d112a5e6c01c80f87e4b0512872ebe0845834b5a03b76b. +Offline focused Cline cycle/project contracts passed in0.105s; checked-in +all-enabled affected-line lint and unfiltered six-linter whole-file gates +each reported0issues. Fresh Python runtime contracts passed23tests in1.419s; +shell independently passed the same23tests in1.431s. Formatting and diff checks +are clean. No vendor client, installer or positive hosted guard ran locally. + +The actual9d native artifact12713365628 was reacquired and matched its original +API size/SHA, closed21-member ZIP/CRC and inner digest. Every raw body passes +the new scanner, and its original complete single-attempt admission still +passes with all lifecycle/authentication/model qualifications false. The6d +frontend12718201141 was also reacquired: exact source/tree, empty clean-source +streams, all30 command-stream joins and normally closed originalUID/GID1001 +service with no forced stop/kill were reverified. That actual full cycle still +failed at missing-repair-a; its quarantined native details remain unobserved. +The separate owned-directory fault correction has not been applied in this +code commit. Root publication and fresh hosted evidence remain separate gates. diff --git a/docs/plans/project-install-e2e/cline-complete-project-lifecycle-plan.md b/docs/plans/project-install-e2e/cline-complete-project-lifecycle-plan.md new file mode 100644 index 000000000..2ac6da27e --- /dev/null +++ b/docs/plans/project-install-e2e/cline-complete-project-lifecycle-plan.md @@ -0,0 +1,311 @@ +# Cline complete native project lifecycle + +## Proven starting point and remaining obligation + +Start from published PR525 commit9d01aefb71f572d69dbe5d36c507b235d19c8059, +tree305e48fdd326813ee68236b063e60e9ac9ce7cbc. Genuine hosted runtime +40456413669/native122030717462 passed the measured installed single-tool +attempt in5.67s. Native12713365628 outer SHA256 +bcf0458f258a527f8cbe5aab7e05183a21255bf2565d0bf700ad192ad09734e8 +and frontend12712348650 outer SHA256 +219a305e1db8f1edcd45eec389db4b5fe0293631f1b66176e737544b18413f41 +were independently checked for exact source/tree, canonical unique ordinary +flat closure, CRCs and all30 frontend command-stream hashes. Native inner SHA256 +e00f3b60b009f674fa4b49e5dce080a9fd3a800c692f85c7a1f2a365161d3a79; +frontend inner9669e847eaf8ef287cd308e32250b0325b1d9004caf2451dbd284ede2f682f29. +The actual ten-frame ACP/provider/probe join passes, session +1793079752200_QjCQR_cli/PID6100, and delegated cleanup is closed without forced +stop/kill. All five lifecycle/MCP qualification flags deliberately remain false. + +This next slice proves the complete public UAP and fresh native cycle rather +than treating that one exchange as completion. Preserve the earlier intentional +failures and successful single-attempt proof. Preserve the existing separate +current-source Cline configuration/lifecycle/same-name gate and all legacy +tests; their source-level and read-only discoveries remain separate evidence. +VS Code is deferred and has no work in this slice. No release or new PR. + +## Fixed authority, source recipes and owner + +Reuse the real pinned Cline3.0.73 archive/member, Go/compiler/installer/scanner +identities, ordinary original UID/GID, actual hosted guard, real delegated +cgroup2/NNP and existing OS process supervisor. Keep one original monotonic +origin:150 seconds work/180 total, existing outer service cleanup reserves, +30-second public/config command caps and bounded native duplex shutdown. No +retry, new deadline, root vendor process, cgroup override or host spoofing. + +Use one disposable original HOME, project A and distinct sibling B. Both project +roots remain ordinary genuine Git roots; neither is a user profile. Use the +existing supported original-user custom-provider/model catalog and one held +loopback listener for the whole cycle. Author that config once before its +protected baseline; never change HOME/catalog/key/endpoint between native +stages. No actual vendor account, OAuth or real model is involved. + +Freeze independently authored recipes before each public mutation: one user +skill-only package and two mixed project packages. Use the same portable +declared plugin name in user/A/B to exercise separate receipt authority, with +distinct user/A/B skill names and markers; A/B use the same owned server name +uapclinea so native source selection cannot hide leakage by renaming it. +Project A starts revision a-one, B b-one; A's explicit later source revision +is a-two. Every recipe captures exact manifest/MCP/skill/probe bytes, package +digest and source identity before UAP sees it. Do not derive expected source, +transport or ownership from installed bytes or a returned receipt. + +Seed unrelated user and A/B skills plus original-user MCP and project MCP +markers before installation. Use only the already source- and native-observed +Cline3.0.73 disabled remote marker shape from the preserved research lane +(nested transport streamableHttp to loopback port9, disabled=true). Do not mark +UAP-owned entries disabled or edit an emitted file to make startup convenient. +Foreign fields/entries/skill bytes remain exact throughout. The seed leaves a +real foreign config after owned removal, so a fresh empty native source can be +tested without inventing a replacement config or falling back to user state. + +## Finite public and native sequence + +The public table contains exactly15 unique commands: git-a, git-b, version, +add-user, add-a, add-b, repeat-add-a, unchanged-update-a, intact-repair-a, +update-a, missing-repair-a, remove-a, repeat-remove-a, remove-b and remove-user. Public operations +use the public installed CLI, exact selected scope/target/source and explicit +project-root where applicable. No native command is called by public mutation. +Keep exact whole-JSON success/mutation semantics and expected progress output. + +1. Observe empty A/B via fresh pinned native config skills/MCP and fresh ACP + startup with the original-user model catalog, each selecting only its actual + fixed project file. Require no owned tool declaration or probe event. +2. Public add user/A/B; strict-decode current StateFileV2 with duplicate and + unknown-field rejection and exact domain.StateSchemaVersion, without Store + migration/adoption. Verify selected source/package, Prepared binding, + materialization, physical/client/data IDs, native object receipts and exact + complete installed payload against the prior independent recipe. Public user + state remains user authority; project receipts cannot authorize its paths. +3. Fresh native skills/MCP listings in user/A/B prove exact selected paths and + markers. Fresh ACP in A and B each permits one exact installed call, writes + its scope data marker and joins provider/native/probe facts. Verify original + user and sibling snapshots before/after every operation. +4. Repeat A add and unchanged A update preserve exact idempotent state/native + bytes. Intact repair retains independently expected native bytes and stable + identity while respecting its existing truthful mutation result. +5. Author A-two by one explicit controlled change to the fixture-owned source + files after verifying the held A-one recipe. Capture a new immutable recipe + before public update; retain historical A-one evidence. Do not change + installed bytes directly. Public update must preserve installation/client/ + physical/data identity, move only the expected package/source revision and + update selected A skill/MCP payload. User and B remain byte-identical. +6. Fresh A native startup performs a read operation: A-two runtime revision, + exact package/data authority and the original A data marker must survive. + Require a new native session and fresh probe PID/session/event interval. +7. After verifying recorded ownership, remove only the ordinary owned A skill + leaf as the controlled missing-object fault. Public repair restores exactly + the frozen A-two recipe and stable IDs; another fresh native A read proves + A-two and retained data, while foreign/user/B bytes remain unchanged. +8. Public remove A removes only recorded owned A skill/MCP/package projections; + verify the remaining installation has no client binding, DataRetained=true + and its original owned DataReceipt, data directory, ownership marker and + written marker bytes. Default removal does not purge data or consume that + receipt (domain.DataReceipt and usecase.finalizeLastBindingState). Preserve + foreign config, user and B. Fresh A ACP and native + listings must contain no removed owned A tool/skill and produce no A probe + event. Fresh B ACP still reads B-one and its original marker. + Repeat the identical public A removal as repeat-remove-a before removing B + or user. The current public explicit-target path is runRemoveMany; + removeManySession.buildInputs rejects the retained installation's absent + binding before rendering success JSON. Require exactly exit1 with no + process/context/capture/cleanup error, empty stdout and the + exact stderr line `agentplugins: plugin is not installed for target "cline" in project scope; no target was changed\n`. + This is the sole expected refusal, not a successful no_change JSON result. + Keep the existing strict process.OS supervisor: osrunner.go's + splitCommandWaitError/commandResultFromWait normalizes its exact natural + *exec.ExitError to that nonzero result with err=nil only after clean + containment; a wrapped cleanup, context or capture error remains fatal. Do + not replace the supervisor to expose the raw Wait error. The recorded + error=false/error_kind=none is truthful about that API, while exit1 and the + exact refusal bytes describe the public command outcome. + Capture its full triple and finite error-kind receipt. Require byte-identical + retained state/DataReceipt/data/ownership/marker, foreign files, user and B + before/after; never accept arbitrary not-found errors or synthesize flags. +9. Public remove B and user with the same default no-purge semantics; verify + their binding removal and owned retained-data receipts, including the user + receipt established at final binding removal if not already present. Fresh + final A/B native listings/startup show no owned cycle skill/tool. Foreign + user/project entries and A/B marker bytes remain exact, no removed package + is restarted and all descendants are gone. + +The following listing matrix is fixed before source edits. U denotes the +distinct user skill marker; A1/A2 and B1 denote the distinct project skill +markers and their frozen a-one/a-two/b-one recipes. Every row has exactly one +config-skills and one config-MCP command with exact pinned argv. Original user +skills remain discoverable from both project roots; project MCP selection uses +only the exact public prepared project file. Outside means an ordinary cwd +outside A/B using the genuine original default user source. Foreign seeded +skills and disabled MCP entries are additional, byte-identical at every row. +No row may contain the sibling's owned marker or use source fallback. + +| Listing stage | Cwd / MCP source | Owned skill markers | Owned MCP recipe | +| --- | --- | --- | --- | +| empty-a | A / A prepared file | none | none | +| empty-b | B / B prepared file | none | none | +| installed-user | outside / original user default | U | none | +| installed-a | A / A prepared file | U, A1 | a-one | +| installed-b | B / B prepared file | U, B1 | b-one | +| stable-a | A / A prepared file | U, A1 | a-one | +| updated-a | A / A prepared file | U, A2 | a-two | +| repaired-a | A / A prepared file | U, A2 | a-two | +| removed-a | A / A prepared file | U | none | +| remaining-b | B / B prepared file | U, B1 | b-one | +| removed-b | B / B prepared file | U | none | +| removed-user | outside / original user default | none | none | +| final-a | A / A prepared file | none | none | +| final-b | B / B prepared file | none | none | + +The ACP matrix is also fixed. Every calling row selects only that project's +receipt-authorized root/data/argv and the same owned server name uapclinea; +each has a fresh native session and probe process. A/B data markers are distinct +and retain the original values and owned identities through update, repair and +default removal. Empty rows forbid owned declarations, permissions and probe +events; their marker-absence or retained-marker equality is independently +checked, without deleting retained data to manufacture absence. + +| ACP stage | Project | Revision | Operation | Required data / absence proof | +| --- | --- | --- | --- | --- | +| empty-a | A | none | empty | No owned tool or probe; no A marker yet | +| empty-b | B | none | empty | No owned tool or probe; no B marker yet | +| installed-a | A | a-one | write | Write exactly A's frozen marker | +| installed-b | B | b-one | write | Write exactly B's frozen marker | +| updated-a | A | a-two | read | Read original A marker with stable IDs | +| repaired-a | A | a-two | read | Read original A marker with stable IDs | +| removed-a | A | none | empty | No owned tool or probe; retained A marker unchanged | +| remaining-b | B | b-one | read | Read original B marker with stable IDs | +| final-a | A | none | empty | No owned tool or probe; retained A marker unchanged | +| final-b | B | none | empty | No owned tool or probe; retained B marker unchanged | + +Thus five call stages have exactly two provider requests and +five empty stages exactly one: at most15 registered requests for this separate +cycle owner, never a changed request cap for the existing single-attempt owner. +No operation may appear twice or be silently skipped. Existing native same-name +skill precedence observations remain +an explicit vendor limitation, not proof that one same-name skill body is active; +this cycle uses distinct skill markers while exercising identical portable +plugin/server names and isolated user/project receipts. + +## Reuse the measured grammar, with an explicit empty mode + +Reuse the measured initialize/session/permission/tool/message/info/end-turn +parser and original allow_once decision. Extract only neutral test helpers +needed to supply an independently held stage blueprint: selected scope/root/ +data/argv/revision/nonce/marker/operation. The existing single-attempt defaults, +raw replay hashes and hostile contracts must still pass unchanged. + +Keep one provider listener with a closed registered stage table. Arm only the +next expected stage after the previous native process and its handlers finish; +idle/unarmed or repeated requests fail. Calling stages have exactly two requests +and one exact tool call/approval; read versus write is a finite stage choice. +Do not reset or discard prior requests: retain stage-labelled bounded originals. +Each stage uses a distinct provider call ID/prompt/sentinel, while the authored +package nonce stays frozen across unchanged restart/repair. Fresh native session, +probe process session, interval and event offsets independently prevent replay. + +Empty stages are capture-first and initially unqualified. They issue no tool +call or permission: require zero owned MCP tool +declarations, one scripted text response, exact sentinel/info/end-turn and no +probe events/marker changes. Its initialization/session/message grammar uses +the same pinned ACP implementation, with the tool subsequence absent. Reject +any unfamiliar output, hidden fallback, tool request, permission or source +selection; never synthesize successful native bytes. This absence mode must +receive its own hostile parser/provider contracts and fresh actual raw review +before any runtime qualification claim. The first full cycle deliberately +fails at a final capture-review gate even when every stage appears successful; +all qualification flags stay false. Keep its complete bounded raw evidence for +independent review of the actually observed empty grammar and full authority +cycle. Only a subsequent separately reviewed amendment can retire that gate. +No builtin action is requested. + +All nonempty stages require exact provider/native/probe facts, one initialize, +one-to-three tools/list, one tools/call, the selected receipt paths, expected +revision and retained marker. Events must lie after that stage's held offset +inside its real interval and use one fresh probe PID/session. No field from B, +user, a prior revision/session or a provider-only identifier grants A authority. + +## Mutability and bounded evidence + +Before each planned public mutation, verify the prior complete selected proof. +Permit only the finite selected mutable paths during that operation; freeze +all unrelated original-user, sibling, foreign, source/compiler/runtime/scanner +authority. Independently validate the new selected state against the held +recipe and stable IDs before updating any expected snapshot. Never wholesale +clear protection maps, adopt an observed native rewrite or infer ownership from +success JSON. Controlled source revision and missing-leaf fault are explicit +fixture actions, not exemptions for arbitrary changed installed bytes. + +Retain the existing64-member/1MiB-per-member/12MiB-total native bounds and shared +outer limits. Fifteen public command triples use45 members. Store native ACP, +native command/listing, provider requests/responses/receipts, probe events and +proof snapshots in at most8 fixed aggregate JSONL members plus one summary: +at most54 flat ordinary unique members. Every aggregate record has a finite +stage ID/index and exact bounded raw bytes with byte count/SHA; reject duplicate +or missing stages, unknown keys, overflow and trailing data. Redact the private +fixture key before recording and retain final canary refusal. Enforce live +aggregate bounds as records arrive, rather than truncating at finalization. + +The final summary records the complete registered public/native/proof stage +matrix and exact source. Failed, incomplete and first capture-review cycles +retain all qualifications false. After the new empty grammar/full-cycle raw +evidence is independently reviewed and a separate amendment retires that gate, +only a complete successful cycle after original-budget/provider/process/cgroup +cleanup can set project-lifecycle/native-restart-removal and the three MCP flags +true. Vendor-authentication and real-model remain false. The frontend +must retain the measured single-attempt format as a separate unqualified mode; +add a distinct closed cycle mode and exact required member/stage closure rather +than relaxing its21-member single-attempt proof. + +## Scope, reviews and genuine verification + +No production adapter, state/solver/transaction engine, native source/pin, +auth/trust policy or shared supervisor change. Add bounded Cline-only cycle +fixture/proof/lifecycle/observation/contracts Go test files, and narrowly adapt +the existing Cline test helpers to remove only hardcoded single-stage values. +Update scripts/project_native_runtime.py and its existing inert tests to select +the exact new cycle test for client cline and admit its separate closure. The +existing cline_service owner, runtime workflow and read-only Cline gate stay +unchanged. Keep every new Go file below the existing size/complexity gates. + +Two independent plan GOs precede code. Inert contracts use real file ownership, +current Store writer/loader/planner/Stager projection where relevant, actual +measured grammar replays, and hostile wrong-scope/identity/source/revision/data/ +event/stage/closure cases. Verify current single-attempt and shared-client +contracts remain green. Use only a granted exclusive Go/lint slot; no local +vendor, credential session or host spoofing. + +Independent code review and exact focused/size/architecture/Python checks +precede root-only non-forced publication to existing PR525. A genuine hosted +run must execute every registered stage and independently retain closed raw +evidence, including fresh empty post-removal startup. Review that first failed +capture, make the separately reviewed finite completion amendment, then require +a fresh complete successful source-bound run before qualification and merge. +An unexpected native behavior fails for measured interpretation; do not +weaken the plan to turn a partial cycle green. Preserve all earlier evidence, +user/source/pin/ownership gates and combined integration requirements. + +## Implementation and validation record + +The two reviewed plan commits are dc9c7fc1 and 52e676a9; the latter corrects only +the existing supervisor's natural-exit API interpretation. Code commit +6b19ecaabe263d8d463fb23ea1bcdc9330562b3a has independently reviewed tree +3dccec164c164f27e19994201b1a0d9a35e359e7 and 16 changed source/test files. +Root and both independent critics approved exact manifest SHA256 +f9a43a2d0f09826bdde3c623813aa5ce7bee1df8df7cb1363ac70bc35f1e0fac. +Review fixes close blank legacy-user data authority with exact-zero receipts +and guarded absence until removal, reject malformed/coerced skill metadata, +and inspect bounded nested JSON/JSONL strings before evidence encoding. + +Actual focused Cline cycle/current measured-grammar contracts pass in 0.115s, +including real current Store/loader/planner/Stager/DataManager and loopback +phase fixtures. Affected all-enabled lint and the unchanged whole-file six- +linter size/architecture gate both report 0 issues. The 22 Python runtime tests +pass in 1.571s and 5 shared Cline tests in 0.001s; whitespace checks are clean. +The optional inert shell-only natural-exit control cannot run on this local +proc surface (ErrOrdinaryContainmentUnsupported); its pure refusal controls +pass, and genuine hosted/runtime admission remains fatal and unchanged. +The retained genuine 9d 21-member successful single-attempt artifact re-admits +unchanged with all qualification flags false. No vendor or installer was run +locally. This candidate still requires the genuine full-cycle first capture, +its intentional final failure, independent empty/full-cycle raw review and a +separately reviewed amendment plus fresh complete success before qualification. diff --git a/docs/plans/project-install-e2e/cline-measured-installed-grammar-plan.md b/docs/plans/project-install-e2e/cline-measured-installed-grammar-plan.md new file mode 100644 index 000000000..9edfdc741 --- /dev/null +++ b/docs/plans/project-install-e2e/cline-measured-installed-grammar-plan.md @@ -0,0 +1,175 @@ +# Cline measured installed ACP grammar follow-through + +## Exact genuine observation and scope of proof + +Current PR525 source 8d278b1d0766931be192447733e1e8ffbd0167b5, tree +e1d976688c72828fbb6a1bc38843e4a14348641b, has genuine hosted runtime run +40453454042, native job 122021475603. The test passes its existing source, +public project installation, receipt/ownership, original-user custom-provider, +actual ACP permission and provider/probe checks, then deliberately fails at +agentplugins_cline_project_native_attempt_test.go:704 to await capture review. +It does not fail a native transport, model/provider, or cleanup assertion. + +Native artifact 12711941321 is 29608 bytes, outer SHA256 +15fa9c5af0385974a52abd567e92263aae10f163a5fb583b4e74348b98e75a36; +its runtime.zip SHA256 is +47f125ce97d47cd820704580f3a9349a22f9226979eeebc94ab3b56f9b10f39a. +Frontend artifact 12711871327 is 22999 bytes, outer SHA256 +b915029a0db000128bfd0f9c52cf553b3976c86d2d00d51c6e8be483b26a696e. +CLI independently verified outer digests, canonical unique ordinary flat member +inventories, CRCs, exact source identity and frontend command-stream digests. +The frontend delegated service is closed, forced_stop=false, forced_kill=false, +under original UID/GID1001. The native process used existing planned duplex +shutdown, with auto_approve=false and injected_mcp_servers=[]. + +The ten measured native ACP frames establish initialize protocol1, agent name +cline/version3.0.73, native session1793077736317_iF4rU_cli, and the existing +user-catalog model/provider. The single installed uapclinea__inspect_runtime +call has pending tool_call_update, one exact session/request_permission, +in_progress tool_call_update, pending tool_call, completed tool_call_update, +the exact final agent message, session_info_update, and end_turn result. +Only allow_once is selected by the existing narrow client permission logic. + +Native rawOutput, second provider-request tool history and independent probe +tools/call facts are equal. They join the installed package/data paths, argv, +nonce, revision a-one, marker, PID6091 and probe process session. The three +probe events initialize/tools-list/tools-call are ordered inside the measured +native interval. Provider metadata has error=false, two requests/two responses, +exact_call_issued=true and single_call_approved=true. Raw native-acp.jsonl SHA256 +is 1a4e9a20fe5958b9232bd8d3f1e46c42382c66c61807a91ee133bb39b2a3c8af; +probe-events.jsonl SHA256 is +40f6f77054109fc93e141d1721efd9d50a32676c2631eff1323670fbf1c97284. +The prior genuine source6b76908e/run40397574726 separately captured and passed +the same ten-frame grammar and independent join before the same deliberate +failure. Retain that earlier evidence as history, without relabelling either run. + +This observation proves one source-bound installed ACP exchange. All five +qualification flags remain false, as do vendor authentication and real model +flags. It does not prove the full A/B/user lifecycle, update, repair, retained +data across restart, removal, or successful post-removal discovery. Those remain +mandatory subsequent E2E work; this slice removes only the measured capture gate. + +## Baseline and implementation boundary + +Work starts in an isolated checkout of the exact current commit8d278b1d. +The actual GitHub current tree was independently read and fetched read-only: +the two Cline Go proof files, existing Cline contracts and two shared runtime +Python files match blobs71071c17,ca7d41dc,3502c1fd,854cef3b,dfbb0c86. +Preserve both externally published lint corrections dab49d09/8d278b1d, their +existing exact wire spelling, CI-only overlay and ancestry; do not add lint +suppression or replace an external file with the stale local version. +VS Code is explicitly out of scope. + +Obtain two independent plan GOs before editing implementation. Scope is exactly: +repotests/agentplugins_cline_project_native_attempt_test.go; +repotests/agentplugins_cline_project_native_provider_test.go; +repotests/agentplugins_cline_project_native_contract_test.go for the narrow +existing permission-protocol fixture adjustment described below; +one new bounded Linux grammar-replay Go test file; +two exact nonsecret measured JSONL testdata files; +scripts/project_native_runtime.py; scripts/test_project_native_runtime.py; +and this plan/validation record. Preserve all existing Cline contract cases and +assertions; no other change to that existing contract file is in scope. + +### Freeze the measured proof grammar + +Retain the current strict JSON decoder, closed field sets, response order, +native session format, provider-issued call binding, single permission, exact +tool/title/input, original project cwd and empty session/new mcpServers. Tighten +agentInfo.name to the measured exact cline value. Add a small finite progress +state for the measured tool notifications: pending-update before permission, +in-progress only after that approval, the measured pending tool_call, then one +completion. Reject repeats, missing transitions, out-of-order tool events and +events outside the prompt stage. Final text may arrive in bounded chunks only +after completion and must concatenate to the existing exact nonce sentinel; +retain strict session-info timestamp shape and require the measured final +session-info notification before end_turn. Do not accept new protocol fields, +tools, permission choices, sessions, model/provider IDs or source injection. + +The current installed source/receipt/tree checks, provider validation and +native/provider/probe/marker join remain decisive. After all of them succeed, +replace the deliberate fatal capture gate with runtime_attempt_complete=true +and native_exchange_observed=true. Keep every qualification entry false. +Deferred provider closure and original total-budget checks must run before the +final result is written; if any deferred check marks the test failed, reset +runtime_attempt_complete=false so cleanup failure cannot emit success. + +### Meaningful inert replay of actual measured bytes + +Preserve the exact hashed native ACP and probe JSONL streams as small testdata; +they contain disposable fixture paths/nonces and no credentials. Re-read them +with fixed digest assertions. Feed the actual transcript through the existing +f.acp parser using inert readers/writers and the recorded call/session/nonce +inputs, then compare the returned native facts to the recorded probe call and +exercise existing clineAttemptEvents on its recorded interval. Verify outgoing +initialize/session-new/prompt/allow-once messages remain exact, including no +injected MCP servers. No vendor, listener, model, installer or subprocess runs. + +Use differential malformed transcripts from those actual bytes to reject wrong +agent/session/tool/call/arguments, duplicate or reordered permission/progress/ +completion, missing completion/sentinel/final result, unknown fields/methods, +failed tool output and mismatched probe facts/events. Keep existing hostile +provider/installed-authority/session/permission/event contracts enabled. The +existing unknown/duplicate-permission ACP fixture currently sends permission +immediately after session/new. Add the actually measured pending +tool_call_update before that permission, so its first valid allow-once and +second duplicate cancellation assertions continue to exercise their intended +boundary after ordering is tightened. Preserve those assertions and all cases. +Put all new replay tests in a bounded file rather than expanding existing large +contract files. + +### Preserve closed artifact admission for both outcomes + +Retain the current failure diagnostic branch: failed captures still have +runtime_attempt_complete=false/test_failed=true and all qualifications false. +Add a strict success pair true/false; reject mixed contradictory pairs. Success +requires the existing exact complete 21-member closure: all four public command +triples, both ACP members, both provider request/response pairs, provider receipt, +probe events and summary; no ACP error member. Require public command exit0, +error=false/deadline=false, ACP error=false, exact two/two provider counts, +issued/approved=true/error=false, measured attempt stage/session identity and +native_exchange_observed=true. Preserve exact source identity, version, Prepared +activation, secret rejection, member bounds and every qualification=false guard. + +The shared Python frontend remains an envelope/closure validator, while the +reviewed Go proof owns the native protocol and independent authority joins. +Do not add a second native protocol engine or trust an incomplete summary-only +success. Extend existing Python contracts with complete success and missing/ +contradictory/forged member and receipt cases. Other clients' admission behavior +must remain unchanged. collection_complete then describes this one measured +attempt only; it never implies full lifecycle qualification. + +## Checks, publication and remaining E2E + +After implementation review, use the exclusive Go/lint slot for focused existing +Cline plus new grammar-replay inert contracts and affected all-enabled and +whole-file architecture/size lint. Run existing shared Python runtime-admission +contracts, gofmt/diff checks and exact source/fixture hash verification. No local +vendor or SDK execution, host spoofing, pin change, policy bypass or suppression. + +Root alone publishes reviewed commits to existing PR525. Fresh genuine hosted +source-bound execution must observe the measured exchange and ordinary delegated +cleanup on the new head before the single-attempt gate is considered closed. +Do not relabel the earlier deliberate failure. Then implement and independently +review the remaining full project lifecycle/native restart/removal proof, keeping +user authority, retained data, source movement and authentication as their own +observed gates. No release or new PR is authorized by this plan. + +## Plan review + +Final plan SHA256 e06ee55bd8e1a3010748cae724ded5cd807c06211700ca069b742a7f1dd887eb +received independent desktop R1 GO and shell R2 GO before implementation. + +## Implementation review and actual validation + +Independent desktop and shell code GOs cover the exact eight-file staged tree +9cb20b6090c6d99bb33ac531c46ff2726bfbbea4. Actual final focused TestClineProject +contracts PASS in 0.051 seconds; all 20 shared Python runtime-admission contracts +PASS in 0.017 seconds. Actual golangci-lint 2.13.2 affected all-enabled lint and +the unfiltered whole-file size/architecture gate each report 0 issues. Its sole +initial prealloc finding was resolved with a ten-frame replay capacity before +the final focused and lint runs. The current 8d native archive is re-admitted +as the same failed capture with 21 members and all qualifications false. +Raw fixture hashes and whitespace checks pass. No local vendor ran; a fresh +genuine hosted new-head success and the subsequent complete lifecycle remain +required, with no prior failure relabelled. diff --git a/docs/plans/project-install-e2e/completion-plan.md b/docs/plans/project-install-e2e/completion-plan.md index 431ef0539..73f5dd56d 100644 --- a/docs/plans/project-install-e2e/completion-plan.md +++ b/docs/plans/project-install-e2e/completion-plan.md @@ -1,5 +1,21 @@ # Project installation completion plan +## Owner reprioritization, 2026-10-27 + +The owner explicitly deferred VS Code: it is not a priority and is skipped in +this continuation. Complete the nine remaining client leaves in PR521-529 and +their applicable end-to-end verification, independent review and merge gates. +Keep PR530 as a deferred draft; preserve its existing source, recorded evidence +and unpublished work. Do not run new VS Code qualification, change its dedicated +implementation or merge that leaf as part of this continuation. Its incomplete +qualification does not block the active nine-client program. Preserve existing +baseline regression coverage for previously supported behavior. + +This latest scope decision supersedes earlier instructions below that require +VS Code follow-through or count it among the active remaining targets. It does +not change the evidence requirements for any active client, promote a blocked +native case to passed, or authorize a release. + Owner continuation: 2026-10-24. The owner authorizes practical spikes, independent critique and fixes, parallel implementation for all supported clients, independent code review, incremental commits/pushes, and merge after verification. Publishing diff --git a/docs/plans/project-install-e2e/copilot-exact-message-role-plan.md b/docs/plans/project-install-e2e/copilot-exact-message-role-plan.md new file mode 100644 index 000000000..28c918ff1 --- /dev/null +++ b/docs/plans/project-install-e2e/copilot-exact-message-role-plan.md @@ -0,0 +1,59 @@ +# Copilot: exact message-role membership + +## Concrete finding and isolated scope + +The published Copilot source is `9b8ddc5332d70ca0c8d39c41c5ce60f3bba1c6e7`, +tree `8386a313607a2d1acfd5583bd9335d9ce7af1340`. Its private scripted-provider +validator uses a delimiter-string substring search to recognize message roles. +An otherwise valid full request whose message is +`{"role":"user|assistant","content":"fixture"}` passes that search and every +remaining message/envelope check. `system|developer` and +`user|assistant|tool` provide equivalent counterexamples. Root and an +independent critic confirmed the complete source path statically; this is not +a claim of a new vendor observation. + +The separate nine-lint proposal deliberately preserves the existing accepted +input set. This amendment addresses the semantic enum defect independently, +rather than attributing a grammar correction to formatting or lint cleanup. + +Use an isolated new worktree and branch from the exact published source. +Do not edit another continuation's checkout, integration branch, lint plan, +checkpoint or pending native capture. Scope is two existing Copilot test files +plus this plan/validation record. No production adapter or shared validator +changes. + +## Correction after two independent plan approvals + +In `copilotProjectMessage`, retain the required string type, then use exact +membership over precisely the existing five intended labels: `system`, +`developer`, `user`, `assistant`, and `tool`. Reject every other string with +the existing finite message-role error. Preserve all content/null handling, +tool-call identities, optional fields, declaration/envelope constraints and +provider state transitions. Add no normalization, splitting, case folding, +alias or accepted role. + +Extend the actual full-request contract seam with the demonstrated composite +roles, using the existing valid request recipe and changing only its role. +These cases must fail on the old substring validator and pass after the exact +enum correction. Include positive full requests for each canonical role with +its existing required fields, so the intended five-role grammar is preserved. +Retain all existing unknown-field, malformed-content, tool, provider-return, +privacy and original-config controls. + +## Validation, integration and publication boundary + +Obtain two independent plan GOs before code, followed by two independent reviews +of the exact changed bytes. Formatting and diff checks must remain clean. +Run focused inert Copilot/shared contracts in a free coordinated Go slot; no +vendor executable or positive hosted guard may run locally. Verify the changed +code with the applicable lint gates. Existing unrelated nine-lint findings +remain visible and must be reconciled by the separate reviewed amendment. + +Commit the isolated plan and correction as separate local increments. Do not +push or alter the authoritative leaf while the current `9b8ddc53` native +capture is still needed. Publication remains root-owned after writer +coordination, a fresh exact remote-head check, applicable checks, and semantic +integration with any separately reviewed lint changes. No forced update, new +PR, release or VS Code work. Historical failed captures and all existing +qualification/authentication/model flags remain unchanged; the static fix +does not supply native session or lifecycle evidence. diff --git a/docs/plans/project-install-e2e/copilot-exact-message-role-validation.md b/docs/plans/project-install-e2e/copilot-exact-message-role-validation.md new file mode 100644 index 000000000..681efd1fa --- /dev/null +++ b/docs/plans/project-install-e2e/copilot-exact-message-role-validation.md @@ -0,0 +1,69 @@ +# Copilot exact message roles: validation + +Reviewed implementation: `61d11984c18a4d81d6dfe212b093e81b7b84fde3`, tree +`7c83ae8e4515835ebfc46ff3418a95a7dce9fb4a`. The preceding plan-only commit is +`105c11de6bfc2aae565b7e3770d00d520ab02568`; the published source baseline is +`9b8ddc5332d70ca0c8d39c41c5ce60f3bba1c6e7`. + +## Independent reviews and exact scope + +During the current reconciliation on 2026-10-27, root performed independent +R1 plan and code review, and native_finish performed independent R2 plan and +code review, against exact plan105c11de and code61d11984. Both gave GO for the +exact five-role switch and all14 full-request controls. The imported handoff's +claims of earlier reviews by named workers could not be independently +confirmed and are not relied on. This record does not assert that the current +reviews preceded the isolated original authoring or its19:32 handoff. + +The following hashes identify the isolated source reviewed during that current +reconciliation. The combined leaf preserves the separately approved context, +De Morgan and formatting corrections; its fresh hashes and validation are +recorded with the readiness candidate before publication. + +| File | Reviewed SHA-256 | +| --- | --- | +| `repotests/agentplugins_copilot_project_native_provider_test.go` | `85beec456341a1f0aa63f1dab2a60d91698835f5b38ce239e267a3e81558cc3c` | +| `repotests/agentplugins_copilot_project_native_contract_test.go` | `c4cd17cabf35583584666281144b7cb6e8c9aede73cdc23ede3bf1fb57c10e88` | + +The provider now requires exact membership in the existing five role labels. +The full-request contract exercises all five canonical roles, four composite +strings, and empty, case-changed, whitespace-suffixed, null and numeric values. +The canonical tool message supplies its existing required tool-call identity. +All other message, envelope, tool, provider and original-configuration checks +remain unchanged. No production or shared validator source changed. + +## Actual inert checks, 2026-10-27 + +The regression was first executed against an overlay that replaced only the +provider file with the exact published baseline. The new full-request test +failed as expected, with `system|developer` incorrectly admitted and a nil +validation error. This is an executed counterexample at the actual request +validator; it is not a copied role predicate or a vendor observation. + +| Check | Actual result | +| --- | --- | +| Baseline provider overlay, `TestCopilotProjectNativeMessageRolesAreExactInFullRequests` | Expected failure, exit 1; first composite role admitted; Go package time 0.011 s | +| Corrected source, `^(TestCopilot\|TestProjectNativeRuntimeValidationContracts)` | PASS, exit 0; Go package time 0.044 s | +| All enabled affected-code lint, `--new-from-rev=9b8ddc5332d70ca0c8d39c41c5ce60f3bba1c6e7 ./repotests` | 0 issues, exit 0 | +| Unfiltered `revive,funlen,gocyclo,gocognit,dupl,depguard` on `./repotests` | 0 issues, exit 0 | +| Formatting and diff whitespace | Clean | + +Go 1.26.10 and golangci-lint 2.13.2 used the existing offline module cache. +No acquired vendor executable ran locally. Each validation checked for other +Go work before starting and would terminate only its own process group if a +competing validation started; neither run reported a conflict. The reviewed +source stayed unchanged and clean throughout the executable checks. + +Local closed check logs have SHA-256 values: + +- Baseline counterexample: `d9653603861c7dbd1b71d8b3e4aa290c67a1d13082249650ceade258c71af469`. +- Corrected focused contracts: `631aff5d0f8d4530a90d27fcf9deeb324ac202300b23839893e0f0a0d4e0783a`. +- Each lint log (`0 issues.`): `e92606b0bf483111dff0a120c315ea165821348f31365020e2468a0059095c47`. + +These checks close this narrow static enum correction. They do not claim the +unfiltered all-enabled integration lint passed: the separate nine-lint +amendment still owns its remaining findings. They do not provide native +session, complete lifecycle, vendor-authentication or real-model evidence. +The historical9b8d genuine capture remains deliberately failed; publication and +semantic integration retain the plan's fresh-head and writer-coordination +requirements. No release or VS Code change is included. diff --git a/docs/plans/project-install-e2e/copilot-first-launch-at-recipe-plan.md b/docs/plans/project-install-e2e/copilot-first-launch-at-recipe-plan.md new file mode 100644 index 000000000..4390d678e --- /dev/null +++ b/docs/plans/project-install-e2e/copilot-first-launch-at-recipe-plan.md @@ -0,0 +1,162 @@ +# Copilot: independently author the documented first-launch metadata + +## Exact measured boundary + +Published PR527 head8b2989dd7ede533f4f07f0a50a97cde55488e5ec, tree +033710ee5a863f6f48fa8591df2d246f899a577e, genuinely ran in runtime40468286931, +native job122072045062. The actual test failed at the original-HOME protected +config.json digest guard after5.08s. Native itself exited0/error=false/ +context_error=false in989ms, with empty stderr. Two provider requests returned; +all11 tool facts match native/provider/independent initialize/list/call events. +Native JSONL session grammar admission was not reached. No qualification, +vendor authentication, real model or complete runtime claim follows. + +Closed native12718265970 and frontend12718255932 were API-size/SHA matched, +canonical unique ordinary ZIP/CRC checked, exact source/tree and empty clean +streams verified, and all24 frontend command-stream joins checked. Native +acquisition is the exact finite projection of the frontend record; immutable +1.0.103 archive9aeb4430e9ac9523546db07b227c7aba179a4710a55f9ac29ad143b0f9e1b325 +and binaryf19b3554a6b62605db3a26d5255ebe2a3ee39fcd6a357edb18301ea5037f6f0d match. +The finite audit is /tmp/uap-cli-copilot-current-8b/source-stream-config-audit.json. + +The baseline was277 bytes/one field and the observed file423 bytes. The81-byte +total prefix contains two comment lines; the remaining342 bytes form strict +JSON with two fields. trustedFolders matches exactly; whole semantic equality +is false. The sole absent-to-string member has key SHA256 +563f31c18be4de7735056e3bbd48a15b45ff97f37b1f7adcd48fb5dd31d25905 and +semantic JSON-value SHA256 +4e65989e507498fcb74632571e8bd028f8e6577985d26c04182c16c11e83f1da. +The actual value remains unidentified. Do not reconstruct, decode, adopt or +use it as a clock, session identity, account or native-success authority. + +## Primary publisher schema and pin compatibility + +The exact measured key hash matches only the literal firstLaunchAt in the +verified publisher global-state schema; this identity is a cryptographic +match to a source literal, not a dictionary guess. + +Use immutable github/copilot-sdk@f2b720c8ec368e035a4d5c72b012fd41b0d533e4, +published by the release application at2026-10-22T03:48:44Z with the commit +message Update SDK snapshot for Copilot CLI1.0.103-0: + +- java/sdk/src/generated/java/com/github/copilot/generated/rpc/GlobalStateLoadResult.java: + Git blob9db799b57eb6401b3eb36d7ea1e62e9a2965758a, SHA256 + cffe488557762c29574fb3260337a7cf8e7679ffef7f4a74532d26d6d4cbacd9. + It defines optional String firstLaunchAt as the machine's first-launch time. +- java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerGlobalStateApi.java: + Git blob2d41182ae0a5dcbfcc9ddc2aabc18a675e0ed92d, SHA256 + fcc41b7b629e4351403ec9a360fb49b7d927a7ff20f13330557104d0ef41e41b. + It documents firstLaunchAt among the finite host-bookkeeping writeKey keys; + trustedFolders, credentials, plugin enablement, staff/account state are not + authorized by that write operation. +- nodejs/src/cliVersion.ts: Git blob58bdcb0b65cc595fc9b0e5a36439ac4456f46840, + SHA256e9e679faabd7170fa810401d20410931ffd94a7e34497005b353715d31617423, + explicitly selects1.0.103-0. + +The same two schema blobs already existed at release snapshot +0f7ab2dc70d23b51379a159176e6c833a30c0e57 (CLI1.0.96-1,2026-10-10). +The stable CLI1.0.103 capture supplies the exact same key-name hash and string +type. This is concrete compatibility evidence, not proof that the prerelease +SDK snapshot and stable executable are identical, or proof of the private +writer's missing-field algorithm. Do not invoke an SDK RPC or add its API. +Whether preauthoring this valid input prevents a write requires a fresh +genuine pinned CLI run with the existing complete digest guard. + +The separately verified publisher release tag v1.0.103 points to public +commit17631dc79466e1cf4a3e3f19e9ea907a56217d2c. Its tree has documentation, +installer and issue templates, not the config writer/schema. Do not claim +that current documentation alone supplies an immutable writer implementation. + +## Finite fixture recipe after two independent plan GOs + +Scope only repotests/agentplugins_copilot_project_native_attempt_test.go and +its existing agentplugins_copilot_project_native_contract_test.go, plus this +plan/validation record. No product, provider, diagnostic/parser, shared +fixture, Python admission, source pin or protocol changes. + +Extract the existing original-config authoring block into a small private +Copilot fixture helper, preserving its sole setup call and fresh ordinary +original-HOME path. Independently author exactly two top-level fields: +the unchanged held project-A/project-B trustedFolders array and firstLaunchAt +formatted from the already held nonzero f.started instant in UTC RFC3339Nano. +Use the actual attempt origin, not a fabricated past age or a new clock. +Formatting must not change f.started, its original150-second work deadline, +the180-second total boundary or any process/cleanup behavior. + +Continue writing bare JSON plus the existing trailing newline once with the +same0600 exclusive/no-follow/owned-file mechanics. Keep the exact authored +bytes cloned in originalConfigBaseline and their original protected digest +before the first vendor --version/native command. Existing prior Git commands +are unchanged. Do not prime the profile with a vendor child, read post-native +bytes into the baseline, add the observed comment prefix, add unknown fields, +copy an actual account/state value, or redirect HOME/COPILOT_HOME. + +The complete file digest comparison remains fatal for ANY subsequent byte +difference, including firstLaunchAt changes, removal/addition, formatting, +comments or trustedFolders changes. Keep existing bounded diagnostic capture +and all negative cases. No semantic-equality waiver, allowed-write mask, +expected-digest replacement, unknown-field acceptance or baseline renewal. + +This is a supported independently authored bookkeeping input for a disposable +fixture. It does not assert that a real user previously ran the CLI, grant +trust/permissions/account status, identify the observed hash value, establish +native session identity or qualify authentication/model/runtime behavior. + +## Meaningful inert checks and genuine follow-through + +Exercise the exact helper with an actual fresh owned fixture directory and +a fixed nonzero held timestamp for deterministic testing only. Independently +assert the exact two-key shape, expected UTC/nanosecond string and original +project roots; verify the actual0600 ordinary single-link file, authored +baseline bytes/hash and protected map. Check that a non-UTC held instant +formats the same instant in UTC, with no changed deadline/origin. The real +constructor continues using its actual current f.started. + +Mutate the actual held file separately by changing/removing firstLaunchAt, +altering trustedFolders, adding a foreign key and adding the measured-shape +comment prefix. Each original digest must still differ/refuse, without +mutating either the held baseline or protected expectation. Preserve existing +actual-child fatal guard controls; no new process/hosted mock is needed. +No local vendor or public installer executable may run. + +Run focused existing/new Copilot facts/source/diagnostic inert contracts, +gofmt/diff checks, actual all-enabled affected lint and unchanged unfiltered +six-linter gate in the exclusive slot. Obtain two independent complete code +reviews before root-only publication to existingPR527 with a fresh non-forced +lease. No new PR, release or VS work. + +The next genuine1.0.103 run must prove that all original protected bytes stay +unchanged and expose the next actual guard honestly. If it still writes a +prefix, timestamp or another field, retain that failure and its finite +diagnostic; do not fold an allowance into this slice. The deliberate native +JSONL capture-review gate and all qualification/authentication/model flags +remain unchanged. Complete user/A/B/update/repair/remove/restart/MCP evidence +and any later qualification amendment remain separate required work. + + +## Implementation validation — 2026-10-27 + +The original plan SHA256 above the validation addition was +`82ac6cadbcd50d27bbc9d01b5ed25eb4756f5d7f3e289ea522bf03eff106c359`. +Root R1 and shell R2 independently approved it before implementation. Desktop +and shell independently reviewed the complete two-file implementation and +issued code GOs for attempt SHA256 +`498a09bb8ef49a9f5a225975f0ae8a85febc5131b8ace268d7c2cf51ad0c6481` +and contract SHA256 +`fab361e8189640681b56fa86a938aaf6eded108b2eb95cefaa1b7c58b25ff710`. + +Root verified those exact file hashes and ran the focused inert Copilot/shared +contracts: PASS (0.045s). The affected all-enabled lint gate and the unfiltered +whole-package revive/funlen/gocyclo/gocognit/dupl/depguard gate each reported +zero issues. Formatting and diff checks were clean. No vendor executable, +account action or positive hosted-environment mock ran locally. + +The real-file controls prove the exact two-key bare JSON recipe, private mode, +held non-UTC origin converted to UTC without changing the context/deadline, +zero-origin refusal before any write, and complete rejection of changed or +removed firstLaunchAt, trust changes, foreign fields and comment prefixes. +The existing fatal guard and diagnostic/provider/session behavior remain in +place. The prior 8b native exit-zero capture remains a failed protected-profile +attempt; this source change does not promote it. A fresh genuine hosted run +must show that the pinned CLI preserves the authored configuration, followed +by the remaining independently verified user/A/B lifecycle work. diff --git a/docs/plans/project-install-e2e/copilot-native-env-and-json-refusal-plan.md b/docs/plans/project-install-e2e/copilot-native-env-and-json-refusal-plan.md new file mode 100644 index 000000000..8adc00bda --- /dev/null +++ b/docs/plans/project-install-e2e/copilot-native-env-and-json-refusal-plan.md @@ -0,0 +1,122 @@ +# Copilot measured native environment and closed JSON refusal diagnostics + +## Exact evidence and current source + +Current PR527 branch is 5afd897d4b10de6286d1e0c97d358ec4e15f0250, +tree94aef6b1ddc3cc55c97c0917d46539c64273d670. Local baseline +a51ec63cc094c979ecbf8147ed7ad2f5eed8f8cf has that exact tree and preserves +the externally published runtime workflow blob66fb12161a3d1cfe6992cfeada8fbf44ad54fda6. + +Actual genuine run40408790152/native job121914618336 used pinned Copilot1.0.103. +Closed native artifact12697784970 has outer SHA256 +773c1374fa322f4f52bbcf875d230e6f8643ff53431bbfeabbc4485b4a92d544; +frontend12697996095 has SHA256 +6de4ae11c713bfa6cb0ca9c9042c7678c87f1989d5bec63abbbe62a56846db77. +The installed mcp.json SHA256 +2bb36b95df074e37f845fac66474a0dc1426938386b2703ae71df9453f4c8496 +retains UAP_TEST_LITERAL as exactly "literal ${UNKNOWN} $HOME". +Independent native output, provider request2 and probe tools/call agree that +the native process receives exactly "literal ${UNKNOWN} " plus the held +original fixture HOME. All other eleven facts match selected source/binding, +data, nonce, revision, arguments, once-expanded root, marker, PID and session. +The current validator instead expects the unexpanded $HOME and rejects it. +Separately, original config bytes change277->423 and the retained strict +diagnostic says invalid-json; changed config bytes/cause remain unobserved. +All qualification flags remain false. These are two distinct refusals. + +The publisher's current official CLI reference documents $VAR, ${VAR} and +${VAR:-default} expansion in local MCP env: +https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-command-reference#local-server-configuration-fields +That current documentation corroborates the exact pinned native capture; it +is not asserted to be immutable version1.0.103 source. Repository loader and +nativeconfig contracts preserve unknown strings during materialization; they +do not establish a universal guarantee against a client's own later expansion. + +## Proposed finite native expectation + +After two independent plan reviews, change only the Copilot fixture's expected +runtime Literal to exactly "literal ${UNKNOWN} " + f.base.Home, using the held +original HOME already selected and validated by the existing fixture. Never +derive it from an ambient host HOME or provider-returned value. Do not expand +arbitrary strings, change HOME, accept both forms, normalize captured facts or +modify a production adapter, portable source contract or another client. +Keep the installed/source MCP literal, its captured immutable bytes/digest and +all package/receipt/projection checks unchanged. The unset ${UNKNOWN} text, +unknown argument, once-expanded path and every other exact fact/event check +remain mandatory. This tests documented Copilot-native expansion; it does not +claim that $HOME remains literal in its executed environment. + +Extend the existing actual facts/event contract with a distinct original HOME +and exact positive native value. Add refusal cases for unexpanded $HOME, +foreign HOME, project-as-HOME and changed UNKNOWN text. Construct each negative +consistently in the event and returned payload before invoking the validator, +so an unrelated event mismatch cannot mask the literal assertion. Retain all +existing wrong-authority/session/order/missing/duplicate/extra-field cases. +No new native response or local vendor execution is authorized. + +## Independent profile refusal diagnostic + +Keep the original protected-digest error and comparison fatal and unchanged. +Only when the existing bounded, hash-stable diagnostic has already obtained +both bodies and encounters its existing invalid-json branch, record two +standard-library json.Valid booleans for the baseline and observed bodies and +a finite enum identifying baseline, observed or both as strict-parser failures. +Also record each failing side's finite error category: syntax, unexpected-eof, +duplicate-key, body-limit, structure-limit, key, object-end, array-end, +unexpected-delimiter, nonfinite-number, trailing-data, or other. Determine +categories only through typed errors/is and exact existing static error text; +never emit an error string, raw token, key, value, path, comment or body. +Unknown errors map to other. A valid side is explicitly valid. No JSONC parse, +fallback, relaxed validator, new file read, larger bound, trust rebaseline or +profile mutation is allowed. Existing hashes/lengths and diagnostic statuses +remain intact; extra fields are optional and confined to invalid-json. +No conclusion about JSONC, changed keys or native ownership follows until a +new genuine source-bound capture provides the additional measured diagnostics. + +Extend existing bounded diagnostics contracts with syntax-invalid, +syntactically valid duplicate-key, baseline-invalid, both-invalid, and +nonfinite/structural rejection controls. Check finite outputs and absence of +private sentinel keys/values/errors. Preserve all existing alias/hardlink, +unstable/read/size/deadline/change-limit and fatal protected-digest assertions. + +## Scope and verification + +Scope: the existing Copilot native attempt, its facts contract, diagnostic and +diagnostic-contract Go test files, plus this plan/validation record. Preserve +provider protocol and tool name, source/pins, host admission, original total and +per-command deadlines, trust/permission, native JSONL capture-review gate, +process supervision, artifact admission, cleanup and all qualification flags. +No product, shared behavior, other client or VS Code change; VS Code is deferred +by the latest explicit owner instruction. + +Two independent plan GOs precede a separate plan commit and implementation. +Independent code critics must challenge the source-vs-native semantic boundary +and preservation of the unchanged fatal profile guard. Under the exclusive Go +slot run focused existing/new Copilot facts and diagnostics contracts plus +affected Required changed-line and whole-file architecture/size lint; gofmt and +diff checks. Do not run a vendor locally. Root publishes to the same PR using +fresh actual Git ref/expected_sha, force=false, preserving external changes. +A new genuine hosted attempt must independently confirm the runtime mapping +and diagnose or pass the profile boundary. This amendment itself establishes +neither complete startup nor A/B lifecycle/restart/removal/MCP qualification. + + +## Independent reviews and actual validation + +CLI R1 and desktop R2 independently approved plan SHA256 +43777a8e94b7ff6c8c8afc2aa2b7c108faa03aa16e2d8c55d6350d861a861848 +before implementation. Both reviewers independently approved the four-file +implementation and its final contract precision adjustment: the project-as-HOME +negative now uses a distinct held Project, independently from original Home and +package TargetLocator. The final contract SHA256 is +9e22798bb46b3a0e9558bc271f84e4439ba78dc7525c53a994cf8f0b0937eed3; +other reviewed source files are unchanged. + +Actual focused TestCopilotProjectNative contracts passed in 0.033 seconds. +Actual golangci-lint 2.13.2 affected all-enabled lint and the unfiltered +revive/funlen/gocyclo/gocognit/dupl/depguard whole-file gate each reported +0 issues. Gofmt and whitespace checks passed. Tests used the repository's +existing Go workspace and ran inert fixtures only; no vendor executable ran +locally. A fresh genuine hosted execution on the published source must still +confirm the exact native mapping and report the separate original-config +refusal. No previous failure is relabelled and no qualification flag is raised. diff --git a/docs/plans/project-install-e2e/copilot-user-registration-first-observation-plan.md b/docs/plans/project-install-e2e/copilot-user-registration-first-observation-plan.md new file mode 100644 index 000000000..f76fa9da8 --- /dev/null +++ b/docs/plans/project-install-e2e/copilot-user-registration-first-observation-plan.md @@ -0,0 +1,175 @@ +# DRAFT: one failed-only Copilot user-registration observation + +Status: source-only proposal, not approved for implementation. No repository +source or native selection changes are made by this draft. The published +readiness head is189e00d364ccde805c9ffc6738e61fc58ae277fc, +tree3f6dd05e28e7c6ab009c37d41cf804d6c3907743 on current program basea412ba5e. +Its genuine readiness run40572613104 is queued at proposal preparation. +Do not advance the leaf while that current capture is pending. First require +its source-bound raw audit and a genuine successful readiness observation; +all five lifecycle/MCP and account/model flags still remain false. + +## Why a full-cycle plan remains premature + +The prior full-cycle draft's three initial prerequisites now have concrete +source/evidence: the genuine9b capture, finite measured readiness grammar and +separately reviewed exact-role correction. Actual native user-registry file +mutations, user/project catalog namespaces and precedence, and a zero-tool +provider/native grammar remain unobserved. Do not fill them with project-only +catalog rows or a guessed user namespace/empty-tools schema. + +Immutable publisher SDK github/copilot-sdk@f2b720c8ec368e035a4d5c72b012fd41b0d533e4 +is the documented1.0.103-0 snapshot, not the private stable1.0.103 writer. +Verified primary schema receipts are in +/tmp/uap-copilot-user-schema-f2b720c8/receipts.json: + +- InstalledPlugin.java blobe3720494033ae53e960a7f1a57d74fb6527b360a, + SHA256e92c8f8b54cb9637fef8b4dd242328bc6e54c2b23746ca2af4e45428c2f6bdca. + It distinguishes persisted installedPlugins records from installed_from + records for live local/directory marketplaces; the latter are never persisted. +- InstalledPluginInfo.java blobdd4beb1722adf5802b51e07a5f474660d7a0bdac, + SHA25679702bf729d937e7e3f3f6941a7d0ffe61e8f5aa79734d952465d36e210c921c, + distinguishes live, installed, direct and builtin metadata. +- McpSourcePlugin.java blob7f4fed4c9c96401a8193a566737368073459b7de, + SHA2568e0390f08728e4379ac8517923bc7950bd4e51f0c3541a40db1c3956a3c80543, + supplies metadata identity fields, not a native tool-name prefix or precedence. + +These narrow facts explicitly prevent assuming a local marketplace necessarily +writes a persisted installedPlugins row. They do not authorize any unknown +file mutation, SDK RPC or broad writable original-profile frame. + +## Exactly one new native boundary + +After two independent plan GOs and the current readiness raw review, introduce +one separately selectable genuine hosted test for a user-registry first +observation. Preserve the successful readiness entrypoint and its contracts. +The eventual collector selection changes only the existing copilot case to +this explicit new test/opt-in for one first capture; no second automatic client +row, workflow, retry or simultaneous superseding push. The previous readiness +capture remains bound to its published source. + +Use the same genuine constructor, official client/scanner/source pins, closed +environment and one original disposable HOME. Keep firstLaunchAt independently +authored from the original fixture start and exact A/B trusted folders. Reuse +the same version/Git/original-config/package preparation through a narrow +private extraction from existing setup, without changing readiness's sequence. +The new diagnostic prepares A/B Git directories and the ordinary independently +authored public package but does not install project A or start a chat/session, +provider, SDK RPC or tool call. User and future project coexistence are not +claimed by this observation. + +The fixed outer command sequence is git-A, git-B, version, add-user only. +The sole new boundary is the real public command from the held outside cwd: +agentplugins add --no-save --scope user --target copilot --format json. +Use the original f.env, actual public native marketplace/plugin backend and +ordinary descendant supervisor. The user operation must keep its existing +native registration/install/list fallback behavior. No direct user-registry +write, activation attestation, --external-uninstalled, login/token/account, +manual success or mock native executable is included. + +Each command retains its existing30-second cap and the original150-second +work/180-second total origins, capture limits and strict normal cleanup. +The fixed matrix is not a reason to extend a deadline or run after exhaustion. +No native child may run after an original-profile or process gate has failed. +Authentication or a native policy refusal remains an actual failed boundary. + +## Original authority stays closed + +The existing original config digest guard remains unchanged and fatal before +and after the public command. It is expected to reveal whether this real user +operation changes it, but the plan does not assume such a change. No observed +profile rewrite can become the new baseline. Existing immutable executable, +source, scanner, configuration and process gates remain in force. + +Before add-user, retain a bounded no-follow metadata inventory of only the +known ordinary HOME/.copilot directory. A deferred read-only observation after +the command (including after a fatal post-command guard) may compare it with +another bounded metadata inventory. It starts no child and adopts no map. +Use ordinary held parent identities, current UID/GID, no-follow checked reads +of directory entries and checked descriptor closes. Refuse aliases, special +files, hardlinks, changed linked/held identities, context exhaustion, depth>32 +or entries>1024. Do not traverse ambient HOME or inherited auth locations. +Unknown paths remain unknown, failed observations. + +The exported diagnostic is finite and at most2KiB: registered stage/status, +before/after entry counts, bounded changed-entry count/omitted count, and at +most16 deterministic sorted records. Each record contains only SHA256 of the +relative path, fixed kind categories, permission integers and booleans for +presence/owner/group/identity/mode equality. Do not read unknown file contents, +emit actual path/name/value/body/exception strings or hash possible auth file +contents. The existing config diagnostic may retain its already reviewed +finite key-name/type/equality/hash facts. This adds observation, never mutation +authority. Refused or incomplete inventory gets only a fixed refused status. +A parent or inventory failure cannot mask the original command/guard failure. + +The actual public stdout/stderr/command receipt are retained through existing +bounded capture. They are not substituted for a native plugin catalog. If a +probe event file unexpectedly appears, retain it under the existing safe bound +and keep the attempt failed; do not infer a tools or runtime qualification. + +## Closed failed-only output and finalization + +Use a distinct explicit copilot-user-registry-first-capture mode. It always +reports test_failed=true, runtime_attempt_complete=false and all five/account/ +model flags false. Keep the exact current readiness and historical failed-only +admission unchanged. Fixed stages distinguish a real setup/public/guard stop +from reaching the deliberate final user-registry-review fatal; no failed +boundary is relabeled as an intentionally completed cycle. + +At most15 members fit existing bounds: four command triples, one summary, +one finite profile-metadata diagnostic and one optional probe log. Complete +triples and a genuine ordered finite prefix are mandatory; no provider request, +native chat stream, invented output or open-ended filename allowance is added. +Source/tree/committed/empty patches and exact acquisition/scanner identity must +match the new source. The failed-only reader may admit a truthful failed prefix +but never collection completion or a qualification. Actual outer test failure +and strict ordinary cleanup remain visible. Archive/write errors remain errors. + +This one capture answers only what this actual user public operation returned +and which bounded original-profile metadata/config facts changed or refused. +It does not establish a permissive registry frame, user plugin loading, source +namespaces, precedence or empty-provider grammar. Any later allowance requires +an independently authored recipe from exact source plus new raw review. + +## Gates and follow-through + +Two independent exact plan reviews precede code. Obtain independent exact-code +review and the coordinated Go/lint slot before focused contracts, actual root +all-enabled lint and unchanged whole-root six-linter gates. No vendor or public +installer executable runs locally. Inert controls use real ordinary files and +bounded metadata inventory: aliases/specials/hardlinks, same-bytes replacement, +parent identity changes, unknown private names, count/depth/deadline exhaustion, +projection bounds and failure precedence. They must prove no private value +leaves the projection and no failure can qualify this mode. Preserve existing +readiness/new-mode/legacy admission tests and exact test-selection contracts; +never fabricate a positive hosted guard or weaken process containment. + +Root alone publishes on a freshly reconciled expected head after the current +readiness capture and its source-bound audit finish. The new genuine first +observation intentionally fails until independently reviewed. Keep its exact +actual prefix and raw artifact identities. Full-cycle design resumes only when +user-registry mutation authority, user/project catalog namespaces/precedence +and zero-tool wire grammar each have their own source or measured evidence. + +## Accepted current execution record + +Root R1 and native-finish independent R2 approved exact draft SHA256 +`84b24bf24240ea52cfed5211dc23463874a2a03066449cbf39c57e57d5b52072` before code. +R2 requires the complete serialized projection, including header and counts, +to fit 2048 bytes independently of the maximum sixteen sorted records. Select +the fitting sorted prefix and keep the true changed and omitted counts. + +The prerequisite then passed genuinely at exact published189e00d3/tree3f6dd05e, +run40572613104/native job122437209141. Desktop raw audit +SHA256740c6454b2d54236adc8fbe81d2eca9592c2257c13bcb007f71bb822de33aee2 +and separate CLI raw audit +SHA256702481a4d1c8b5d940c6fd572aef5d041c5481042fac23e0c08f9ec33b802c5d +verified the native/front bytes and complete readiness joins. All five, vendor +authentication and real-model flags remain false. Root explicitly released the +implementation hold after these current-source observations. The original +proposal status above records its preparation chronology, not a remaining hold. + +Implementation is isolated from the successful readiness checkout and preserves +its callable entrypoint and raw fixtures. The user-only mode must remove inherited +provider/Prepared defaults because neither is observed by this new capture. +No source edits, validation or native success are claimed by this plan record. diff --git a/docs/plans/project-install-e2e/copilot-user-registration-first-observation-validation.md b/docs/plans/project-install-e2e/copilot-user-registration-first-observation-validation.md new file mode 100644 index 000000000..f989e286d --- /dev/null +++ b/docs/plans/project-install-e2e/copilot-user-registration-first-observation-validation.md @@ -0,0 +1,143 @@ +# Copilot user-registration first observation: exact implementation validation + +## Reviewed source and prerequisite + +The accepted plan commit is `24ffbce31311eecbbb32cc3857f7b12c7870de53`, +following exact successful readiness source +`189e00d364ccde805c9ffc6738e61fc58ae277fc` on program base `a412ba5e`. +Root R1 and native-finish R2 approved plan SHA256 +`84b24bf24240ea52cfed5211dc23463874a2a03066449cbf39c57e57d5b52072` before code. +The prerequisite's two separate source-bound raw reviews are recorded in that +accepted plan. Neither review turns its five lifecycle/MCP or account/model +flags true. + +Code commit `a2f312ee27f6d15202edbfd12d8fad4c01381d2c`, exact reviewed tree +`ca9013594bd728ece3d0bb47e3192187b130fd42`, changes ten code files. Root and +independent CLI reviewers read the complete source, shared guards and accepted +plan and gave exact-tree CODE GO without remaining findings. No code changed +after those reviews. This record does not attribute the author's test execution +to either static reviewer. + +The old readiness entrypoint remains callable with its original opt-in. Its +entire function body and both existing readiness semantic-reader files are +byte-identical to the successful source. Preparation is a private extraction +with the original Git/config/version/package sequence. Only the explicit new +mode uses the closed four-command matrix, user/outside scope and failed-only +finalization. The canonical Copilot selector selects that new diagnostic; +there is still exactly one automatic Copilot row. + +## Actual gates + +The following checks passed on the unchanged reviewed code with Go 1.26.10, +golangci-lint 2.13.2 and serialized local validation: + +- Focused `go test -p 1 ./repotests -run '^TestCopilot' -count=1`: PASS, 0.290s. + Existing inert loopback protocol tests used local loopback permission; no + vendor or public installer executable ran. +- `PYTHONPATH=scripts python3 -m unittest test_project_native_copilot_user + test_project_native_copilot_readiness test_project_native_runtime`: 42 PASS, + 7.184s. An earlier invocation without the required module path failed to + import the modules; it did not run the contracts or alter source. +- Actual all-enabled full-root lint with + `--new-from-merge-base=a412ba5e137fdcb7e004393229b323211ed746e1`: zero issues. +- Unfiltered whole-root revive/funlen/gocyclo/gocognit/dupl/depguard: zero issues. +- Four Python files parsed; gofmt and staged whitespace checks were clean. + +Separately, the actual current189e successful native ZIP replays through the +updated shared reader: 21 members, runtime/collection complete, test passed, +all five/account/model qualifications false. Its inner SHA256 remains +`4cb870b0a2c80ac1be98a36db2b58868f6ba8af9187d52092f7a3d6042a42de7`. +The older genuine failed fixture and its manifest remain unchanged. No old +capture was rewritten into the new mode. + +## Boundaries demonstrated and remaining + +The new real-file controls cover unreadable private bodies without content +reads, unknown names and values absent from exported metadata, exact root- +inclusive 1024-entry and depth32 bounds, aliases/FIFO/hardlinks, same-byte inode +replacement and mode facts, coherent parent replacement, original-context +exhaustion, and deferred observation through Goexit. Projection checks cover +full counts, deterministic unique hash order, true omissions, and the complete +serialized object capped at 2048 bytes independently of at most16 records. +Command/reader controls refuse partial or out-of-order triples, wrong scope, +cwd, flags, deadlines, source/scanner pins, unexpected provider/native/installed +members, false completion, qualification promotion, private diagnostic values +and a later review-barrier label masking an earlier process failure. + +This mode performs no project install, native chat/session, provider or SDK RPC. +It creates no account, login, trust or direct registry state. Original immutable +and config-digest guards, ordinary descendant supervision and original +150-second work/180-second total/30-second command budgets remain required. +Unknown file bodies are never opened for reading by the metadata walk. + +No user-registration native observation is claimed by these inert checks. +The next genuine hosted capture is intentionally failed and must be reviewed +at its actual source-bound boundary. All five, vendor-account and real-model +flags remain false. A full lifecycle, user/project catalog precedence and +zero-tool provider grammar still require their own source or measured evidence. +Root alone owns publication and fresh-head reconciliation; no release is made. + + +## Exact disabled-builtin empty registry correction + +The genuine source2c2ac7f1758514f61fc1c88cabc4ad89d6612625 capture in +run40599529602 reached only the intended empty-registry review barrier. +Native12778157833 contains14 members; frontend12778237718 contains25 with24 +stream joins. Both independent raw reviews verify the exact138-byte stdout: +no installed plugins followed by disabled builtin browser-use v0.0.4, under +Copilot1.0.103. Its SHA256 is +`f09cb232e9a7f7bd379daed96099ea1fdf8f6644dcc390ce43c7854874d7e879`. +The existing generic parser treats this whole output as Indeterminate. The +metadata records three changes with zero omissions, but exposes no path roles +or ownership exception. Inherited Cline also completed successfully and was +independently audited before the next publication. + +The accepted narrow production plan is committed at +2ab397bf76b59ff8f8152991643a3c90dbd1d2f0, plan SHA256 +`eca2d5c8d5a29b8a0ce08566cbc3f0712013029db87700cac38ebeea0e2dfd65`, +after root and independent Kimi PLAN GOs. Code +4eba242630e518723d80d325ca20bf03ab9ffe40, tree +671ea6346df418303367b5f24f4bc7455dea0ba3, has two independent full CODE GOs: +Kimi receipt0059958e23f5186ad39d519d7033be51986955c1fa86f3fcaa538766bd8a5eb5 +and native receiptb56069c17151aeec61df9f80b4e811fe4721dffd96c6dd0159268d81d3b069c4. +Root authored this code and does not count as its independent code critic. + +The production branch requires exact whole observed bytes, the held Copilot +client and user scope, nonproject target context, a nonempty canonical name +other than browser-use under case-insensitive comparison, and a successful +ordinary native registry command. A post-run context check also refuses a +runner that cancels while returning exit0/nil. It returns only Clear for the +unrelated requested identity. Generic classifiers, old shared tests, VS Code +and Copilot adapters, original runner/full-tree grace and original first-add +entrypoint/guards remain byte-identical. Only the canonical Copilot test/file/ +optin selection and its expectation return to the original public-first-add. + +Measured current-code local gates with Go1.26.10 and golangci-lint2.13.2: + +- Nested product-module old/new shared Copilot and Copilot adapter contracts: + 7 top-level tests, no skips, both packages PASS. The new tests use only an + in-memory tree-aware runner and independently authored exact text. +- Six Python contract modules:73 PASS in18.436seconds, including runtime, + Copilot/readiness/user/empty-registry and service controls. +- Actual affected all-enabled lint against + a412ba5e137fdcb7e004393229b323211ed746e1: zero issues in both root and nested + product module. Whole unfiltered six linters: zero issues in both modules. +- Historical189e readiness21-member pass,922 user14-member failure and2c2 + empty14-member failure each replay identically through their original full + reader and current full reader. All original bytes/hashes and allfivefalse + qualification outcomes are preserved; none is promoted by the parser fix. + +The local-gate receipt SHA256 is `007515fa75fe69a3595eb1824ed57dea325489a4d87ca25f3ee3d6df0cc13690`. +The original two strict process tests cannot execute on this local host's +missing /proc task/children interface. They were not modified, newly excluded +or rerun solely to repeat that capability failure. The actual2c2 full hosted +Go gate proved both RUN/PASS with no skips; that historical pass is not counted +as a fresh-source pass. The unchanged workflow still requires the complete +unexcluded Copilot/native-runtime Go command to pass before the next native +job. No new source-native outcome is claimed here. + +The next fresh hosted public-first-add capture remains deliberately failed-only: +allfive/runtime/account/model false, even if it reaches its final review +barrier. Earlier fatal command/profile/cleanup failures retain their original +failure boundary. No profile adoption, warmup, trust, provider, prompt or probe +is introduced, and no release or VS Code work follows. diff --git a/docs/plans/project-install-e2e/grok-origin-route-diagnostic-plan.md b/docs/plans/project-install-e2e/grok-origin-route-diagnostic-plan.md new file mode 100644 index 000000000..06bc6ccf5 --- /dev/null +++ b/docs/plans/project-install-e2e/grok-origin-route-diagnostic-plan.md @@ -0,0 +1,61 @@ +# DRAFT: Grok first rejected GET — finite origin-route observation + +Status: research/pre-code only. No implementation is authorized by this document until the owner/root obtains two independent plan-review/fix rounds. This research worker made no repository changes and ran no Go, lint, or Grok executable. + +## Scope and inspected source + +Read AGENTS.md, docs/PROJECT_INSTALL_OWNER_SCOPE.md, docs/AUTHORING_CAPABILITY_PRESERVATION.md, and docs/plans/project-install-e2e/completion-plan.md. Observed /tmp/uap-grok-publish at c6c58579674e0bdb230a556f0bef1de38ce40612 with a clean short status. Root owns all checkout, checkpoint, manifest and remote mutations. Preserve parallel work in both existing checkouts. VS Code is deferred, no release is authorized, and legacy capabilities remain preserved. + +Relevant current files: repotests/agentplugins_grok_project_native_route_test.go, repotests/agentplugins_grok_project_native_provider_test.go, scripts/project_native_runtime.py and its focused runtime-admission contracts. The current finite Go URI observer and the Python grok_provider_route_observation validator recognize exactly /v1/chat/completions, /chat/completions, /v1/models, /models, /v1/responses and /responses; all other RequestURI strings become other in the observer. The separate unchanged provider admission guard allows only the literal POST /v1/chat/completions plus its existing loopback/Host/URL/MIME predicates and exact fixture bearer check. + +## Genuine new blocker and limits + +Exact source c6c58579674e0bdb230a556f0bef1de38ce40612, tree a9c7f08283d631d8e0af2e448601b89f201dbc43; run 40569312299, job 122421982285. Native artifact 12766872743 outer ZIP SHA256 9696d09f9d1f94a868d1830da142a373e4a38ea671c5baca89935a0fec6b075d (4673 bytes); frontend artifact 12766048484 outer ZIP SHA256 b856a564db2322a913318d5955a54d086871851fa2ff0faaf74e5222a0c3205e (3391 bytes). The root independently audited both outer/closed ZIP archives at /tmp/uap-additional-grok-c6-audit-u8yod99g/archive-audit.json. + +The migration sentinel prevents the previous full-config fatal. Genuine native inspect succeeds with projectTrusted=false, the owned project plugin visible as enabled=false with one skill, prepared only. The first native --single attempt aborts at 325 ms after provider failure=route: observed method GET, URI other, loopback peer and matching Host, relative URL, empty URL host and raw path, missing Content-Type. Admitted requests/responses remain 0/0 and ordinary provider shutdown completes without forced close. Native streams are empty; all runtime qualifications remain false/incomplete. + +The provider checks route before bearer and cancels the attempt context on first failure. Therefore credential_matched=false is not evidence of credential absence, and the deadline=true receipt is not a measured 150-second timeout. other excludes only the six exact observer literals; it does not identify any other path, query, endpoint purpose, or caller. + +## Primary-source research, exact identities + +Official xai-org/grok-build public snapshot 2bdd1d6a6369de0e8c68132ea4539e9abd9e14a8 has a complete 5102-entry tree. All seven cited source blobs were fetched read-only via the GitHub API, verified by recomputing the Git blob SHA1 from the exact UTF-8 bytes, and independently SHA256 hashed. Exact hashes, source URLs and line excerpts are in /tmp/uap-additional-grok-first-route-research.json. + +- crates/codegen/xai-grok-shell/src/agent/mvp_agent/session_setup.rs, blob 061460db05fa95afe7d0fa8aba726c34a7bbec5d, SHA256 266eaf035f690ec57bf62b7d9f06bbf72922b17e07f6cc6229820a015cf05ea7: line 610 spawns sampler transport prewarm using session_sampling.base_url; line 1071 does so on restored sampling base URL. +- crates/codegen/xai-grok-shell/src/agent/mvp_agent/sampler_prewarm.rs, blob ae011abbbfb595ccf79bdac2acf68c7af08a5773, SHA256 2b825cbe4165140211510ae0e77b438acc6349f5ab355683b18e1222b599a254: lines 30–31 spawn prewarm_and_record, whose line 64 calls xai_grok_sampler::prewarm_transport. +- crates/codegen/xai-grok-sampler/src/prewarm.rs, blob 4ee8ad76886f1d28c8a7e1269623fa27e9f5fb3d, SHA256 626aa25d3515423372a812b785f7ccdc090161a3a83dd7a0f4355401602e34e5: lines 70–83 resolve endpoint origin and obtain pooled client; line 200 issues client.get(origin).send().await; lines 218–224 derive url.origin().ascii_serialization(), stripping the inference path/query. +- crates/codegen/xai-grok-sampler/tests/prewarm.rs, blob a806fd1b01327e86e31a1d46177a4eb0c135539e, SHA256 c8bbcd17803f5607650907ce97c499ddb0ccdc29633cb5b259004aaaec50c822: lines 40–44 assert the wire request begins GET / HTTP/1.1. Lines 47–63 assert no content-length, authorization or x-api-key for this public-source test. +- crates/codegen/xai-grok-sampler/src/prewarm_tests.rs, blob e0a65970db6506d125e89f0dffe3c3ad5520ebe0, SHA256 a6e64926e03fe22d2cdcfa8bde780692bdf55a5d7d125e7f4dc25beced8eff5c: lines 12–23 expressly test path/query stripping and loopback port preservation. +- crates/codegen/xai-grok-sampler/src/shared_http.rs, blob e659c7fcc4eb8bba52a3c882fa57f670269c4bf4, SHA256 75e919946fb52b887f9bb0a905d8244596b0228235b1eed8313b76d50f8b5943: source documents GROK_SAMPLER_SHARED_CLIENT=0 (or false) and pooled_client returns SharingDisabled before obtaining a client when this source-defined switch is set. Ordinary sampling still constructs a fresh client. +- crates/codegen/xai-grok-sampler/tests/shared_http_kill_switch.rs, blob 4db871673b5c07023bc3955840397cc478bf90d2, SHA256 43a0dc29fe72e561f125c382a0b58cf9e4a1a2f5d78248ba1b137c9eedcd93d5: source test sets that exact switch and checks two independent sampling clients/connections. + +Public source supports a concrete hypothesis: the first GET may be the transport prewarm to /. Shipping build f50904eaee6c does not resolve in this public repository, so source guidance is not proof of binary equivalence. No current genuine observation identifies / or measures absence of credentials. Do not label the c6 route as prewarm. + +## Proposed next slice: diagnostic only + +1. In grokProjectObserveRoute, add only the exact literal / to the existing closed RequestURI switch. Store that same public fixed literal in the existing URI field. No new receipt field, raw path, URL, request URI, query, header, bearer, body, error text or arbitrary digest is exported. +2. Keep grokProjectProviderRoute, admit, serve, failWithRequest, first-failure locking/cancellation, authored configuration, environment, credential, response, request counters, all deadlines, shutdown and qualification logic unchanged. +3. Preserve other for /?private=..., //, /v1/, escaped/absolute forms and every unknown URI; compare RequestURI exactly, never infer the route from URL.Path. A root-path request with a query must remain other. +4. Update deterministic contract coverage to prove / receives the finite label, GET / still fails existing admission, and first actual refused GET / records only those facts with 0/0 admitted counters and unchanged cancellation. Existing first-error/nonroute-error retention controls remain required. +5. Extend private-value controls with /?credential=private-query (and an unknown root-like value) so no query/body/header text can escape. Keep serialized observation bounded under the existing 512-byte test. +6. Add only the same exact / literal to the Python grok_provider_route_observation diagnostic URI enum. Preserve every closed-field, exact-type, failure-state, contradiction, source, archive, completeness and false-qualification rule. This is failed-evidence admission, not provider request admission. Do not infer the label from URL.Path or admit arbitrary root-like strings. +7. Focused Python controls must admit an authored failed GET / observation under the existing closed provider envelope and reject query, absolute, escaped and other root-like arbitrary URI values. Replay the actual source-bound c6 other capture unchanged, and retain the legacy optional-no-observation envelope contract. No raw old evidence is edited. + +A fixed / label is enough to discriminate the strongest source-derived call path. Hashing arbitrary request data is unnecessary for this slice. No accepted GET, synthetic models listing, guessed health reply, MIME relaxation, bearer bypass, deadline increase or second provider transaction is proposed. + +## Review and verification gates + +Obtain two independent plan-review/fix rounds against this document and the exact inspected c6 source. Reviewers must assess finite-data privacy, exact RequestURI semantics, matching Go/Python diagnostic enums, unchanged admission/cancellation and honest qualification. Root alone implements after those gates, followed by independent implementation review and ordinary exact-head repository verification, including the actual focused inert Go/Python controls and retained failed-evidence replay. No local vendor execution or fake hosted-guard environment is permitted. + +A new genuine hosted native run at the reviewed implementation commit/tree must preserve the existing source/workflow/client/archive provenance and ordinary unique artifact-name/closed-ZIP checks. Record exact run/job/artifact IDs plus ZIP SHA256 and size; audit the original native-inspect and native-attempt streams and provider receipt. A successful diagnostic run may still end in the same intentional route refusal. Preserve all false/incomplete runtime/lifecycle claims. + +Interpretation is bounded: +- GET plus exact URI / proves only that the actual rejected exchange was GET / under the existing envelope predicates. It is consistent with public-source prewarm; it does not prove caller identity or absence of credentials/body. +- URI other remains unresolved. Do not widen this label set speculatively or serve a response. +- Any different first failure is recorded honestly under existing first-error semantics. +- No diagnostic result promotes enabled=false/prepared discovery to native runtime, skill loading, session trust, MCP, model or lifecycle success. + +## Conditional follow-up, excluded from this slice + +If new genuine evidence records exact GET /, the source-defined GROK_SAMPLER_SHARED_CLIENT=0 becomes a concrete narrow fixture-environment candidate. Draft and independently review that separate plan using the new evidence before editing the environment. It would preserve the sole accepted authenticated POST route and suppress an optional source-defined pooling optimization rather than inventing a GET response; new genuine proof would still be mandatory. This document does not authorize the switch or claim it exists/works in shipping build f50904eaee6c. + +If genuine evidence remains other, return to source-driven finite diagnostics without guessing. The prepared Grok leaf and its existing source/tests remain preserved. diff --git a/docs/plans/project-install-e2e/grok-origin-route-diagnostic-review.md b/docs/plans/project-install-e2e/grok-origin-route-diagnostic-review.md new file mode 100644 index 000000000..8379ac0a0 --- /dev/null +++ b/docs/plans/project-install-e2e/grok-origin-route-diagnostic-review.md @@ -0,0 +1,15 @@ +# Grok origin-route diagnostic: preimplementation review + +Exact plan SHA256: `a30c9ab852be76cb1dc4a85c8befb924d095871a89beedaa663d94516575d3f9`. + +Before code changed, independent GPT-6.1 Sol xhigh reviewers approved this exact +revision: `kimi_current_review` R1 and `native_current_review` R2. R1 first +identified a missing matching Python diagnostic enum; that omission was corrected +in the plan and both reviewers then returned GO. + +The scope is only the fixed `/` RequestURI diagnostic label and matching Python +failed-evidence intake. Provider admission, authorization, MIME, configuration, +environment, replies, counters, first-failure cancellation, process budgets and +qualification remain unchanged. Public-source prewarm remains guidance, not proof +that the shipping binary sent `/` or omitted a credential. The environment switch +is explicitly excluded. diff --git a/docs/plans/project-install-e2e/grok-origin-route-diagnostic-validation.md b/docs/plans/project-install-e2e/grok-origin-route-diagnostic-validation.md new file mode 100644 index 000000000..a09c5e8a4 --- /dev/null +++ b/docs/plans/project-install-e2e/grok-origin-route-diagnostic-validation.md @@ -0,0 +1,54 @@ +# Grok finite origin-route diagnostic: implementation validation + +Reviewed implementation: `be852aed7f8c9c87497c0a57e531ccc7a20eae7c`, tree `c26668d31a5e62c3e5852aa15c135f5588f2b31b`. +Baseline: `c6c58579674e0bdb230a556f0bef1de38ce40612`. The approved pre-code plan and its two independent +reviews are retained alongside this record. No vendor client ran locally. + +## Independent code review + +Two independent GPT-6.1 high/xhigh critics returned CODE GO for these exact source +bytes. R1 reviewed the full diff, actual provider admission and inert transport +contracts; record SHA256 `d7ee2e31c04da37c24e0db3907c067fe16accf73cdc3aa8e491636be5b554bbf`. +R2 independently checked the manifest, unchanged provider, finite privacy controls +and failed-evidence intake; record SHA256 `7aa7b86888bca3efed07c271f610fe22f9241a82cabaa691d2792c4e1dc8df53`. +Neither critic executed tests or granted native qualification. + +The functional delta is only the literal `/` in the finite Go diagnostic observer +and Python failed-evidence URI enum. Existing exact POST route/authentication/body +admission, environment, configuration, pins, budgets, cancellation, first failure, +provider replies and all qualification gates remain unchanged. The provider file +SHA256 remains `865265e28731ceee3816ab1d5c4fc137d29d859e6851675d90fbcc867f1daa88`. + +## Executed inert verification + +The root executor ran Go1.26.10 and golangci-lint2.13.2 serially: + +- `go test -p=1 -count=1 -timeout=120s ./repotests -run '^(TestGrok|TestProjectNativeCLI)'`: PASS, package1.119s. +- `python3 -B -m unittest test_project_native_runtime` from scripts: PASS,38tests. + Existing absent-observation and contradiction controls remain included. +- All-enabled affected lint against the baseline: PASS,0issues. +- Unfiltered whole-package revive,funlen,gocyclo,gocognit,dupl,depguard: PASS,0issues. +- gofmt and whitespace checks: PASS. + +The first lint invocation failed before analysis because the selected Go binary +was absent from that validation process PATH. Adding the already-selected toolchain +to PATH resolved the environment error; no source changed. The failed log remains +in the validation record. Final validation report SHA256 `e31b5d1caaf61f228d671926e3f00140d98f70ab52b9e63b47de2dd8ed7c40d1`. + +The unchanged original c6 native ZIP from run40569312299/job122421982285, +artifact12766872743, inner SHA256 +`1c85c32f6f895df7fe5fa6024eb260159c7c6db0a3d0862b67f4a0f948fc4125`, was +re-admitted through the new code with its original source identity. All20member +bodies and the failed summary remain identical. The old GET URI remains `other`; +all five qualifications and runtime completion remain false. Replay record SHA256 +`40820d71ca45d0bda4c05ddd2007ae4525c1cdf74b02852339b0cc1a7fe63c3c`. + +## Remaining native boundary + +A fresh genuine hosted run is required to observe whether the previously refused +GET is exactly `/`. This diagnostic change does not admit that request or establish +its prewarm identity, missing credentials/body, shipping-source equivalence, loaded +skill, MCP operation or lifecycle completion. No pool-switch, route, authentication, +trust, timeout or profile exception is introduced. PR522 remains unqualified until +its applicable native and integration gates pass; this record authorizes no merge, +release or VS Code work. diff --git a/docs/plans/project-install-e2e/kimi-poll-refusal-plan-review.md b/docs/plans/project-install-e2e/kimi-poll-refusal-plan-review.md new file mode 100644 index 000000000..f16290304 --- /dev/null +++ b/docs/plans/project-install-e2e/kimi-poll-refusal-plan-review.md @@ -0,0 +1,22 @@ +# Kimi approval-poll diagnostic pre-code approval + +The exact archived draft kimi-poll-refusal-plan.md is approved before code. Its +historical DRAFT header preserves the reviewed bytes, SHA256 +`d46cac19a760a8cf359a2424a1b649fc0a88d4cd23de5d67aa6658f303ab8771`. +Baseline b2bb2b7f85b5461420f932478b197905e6fc5ad9, tree +b12354b2565a05d14037556f8493b149d7d36ea2. + +Two independent GPT-6.1 xhigh critics returned PRE-CODE GO on2026-10-27: + +- R1 scope_and_route_critic, record SHA256 `09fef3556d2bc854e0a1fd87e202371c0a8db6f8767f261d9f9446e6ae50155e`. +- R2 native_current_review, record SHA256 `17127432aa723572f2dd6ad1f5ff1decbbab0a8371f4e74c6f03c29a119df9db`. + +Both require unchanged early multiple-item guard ordering, separate typed +ValueError outside graceful schema capture, exact20completed-empty exhaustion, +privacy/type/ordinal/2048byte limits and no additional action or qualification. +First-cause retention is mutual across existing row and new poll facts. Inert +sleep controls must replace only the observer module's time binding; global +supervisor timing remains real. Both reviewers performed source-only reviews, +no tests or native execution. Exact code review, executed inert gates, unchanged +raw replay and fresh genuine observation remain required. No merge/release or +VS Code authorization follows from this approval. diff --git a/docs/plans/project-install-e2e/kimi-poll-refusal-plan.md b/docs/plans/project-install-e2e/kimi-poll-refusal-plan.md new file mode 100644 index 000000000..f3eae877f --- /dev/null +++ b/docs/plans/project-install-e2e/kimi-poll-refusal-plan.md @@ -0,0 +1,133 @@ +# Kimi single-tool: diagnose only the two unobserved approval-poll refusals + +PRE-CODE proposal. No implementation until two independent GPT-6.1 high/xhigh +plan reviews. This is independent of the approved production intact-repair fix +in /tmp/uap-additional-kimi-scoped-selection-20261027; preserve that work and its +native byte-stability assertion. No VS Code work or release. Read AGENTS.md, +docs/PROJECT_INSTALL_OWNER_SCOPE.md, docs/AUTHORING_CAPABILITY_PRESERVATION.md +and docs/plans/project-install-e2e/completion-plan.md. + +## Exact observed boundary + +Published source b2bb2b7f85b5461420f932478b197905e6fc5ad9, +tree b12354b2565a05d14037556f8493b149d7d36ea2. Genuine run40569825577, +single-tool job122438517585, failed after12.939s. Native artifact12768461663: +7895B, outer0500d6d9cafb34246f71cfd557db0fca848125d0a4d120cffbefdebe764c4ab3, +inner171da150010ee68b6aa8af632863447ad411c3bcca09f48d9d1d22a6e7ddcd29, +23 closed members. Frontend12768386913:3518B,25members, +outer66746161fca39fda9cdf71bfbe07060e2a1b85b98be4296500bd3fb6143d44da. +Exact-source admission, clean source/tree/build and24frontend stream joins +pass. Root audit /tmp/uap-additional-qoder-kimicall-fresh-ka537i9_/audit.json +SHA2569d48d60ff30934eda04e370893e74e130ed9d1843289b3d660c1e14cbbec02cf. + +Public add succeeds Prepared. Actual probe events contain initialize and +tools/list, no tools/call, and one provider request is retained. The collector +emits only its closed generic failure: stage=approvals,phase=validate, +exception_kind=validation,observer_entered=true,service_recorded=true. +Cleanup reports group_reaped and port_closed, no forced kill, SIGTERM sent, +no shutdown acknowledgment. Private service/HTTP streams remain quarantined. +No approval_refusal optional facts or python-api.json were exported. All five, +runtime-complete, authentication and real-model flags remain false. + +The source already projects finite facts for strict single-row ValueError via +kimi_approval_facts.Refusal. It deliberately leaves ResponseSchemaRefusal and +its separately reviewed graceful branch unchanged. The current approval-poll +loop can also raise a generic ValueError when more than one pending item is +returned, or when all20polls finish without a selected approval. These two +refusals carry no finite explanation today. The raw result does not establish +which occurred. Elapsed time is not proof of polling exhaustion. Do not infer +an actual approval shape, request count, native turn ID, missing permission, +tool execution, timeout or binary/source defect from this failed envelope. + +## Narrow implementation + +Add a separate typed ValueError subclass for exactly these existing two +polling refusal sites (including the duplicate post-shape multiple-items +check, if retained). Construct it using only a fixed reason and caller-owned +poll ordinal; pass no pending row, value, exception text, session, ID, path, +body, credential or arbitrary native text. + +Finite public object, provisionally: +- topic: single-approval-poll +- status: refused +- reason: multiple-pending OR no-pending-after-polls +- polls: exact integer1..20; no-pending-after-polls requires exactly20. + +A dedicated strict validator rejects unknown/missing fields, nonexact builtin +types (including bool-as-int), unknown reasons, impossible counts and arbitrary +strings. It returns an independent copied object. Keep the existing single-row +Refusal/project/validate API and its facts unchanged; use a separate method/type +in the existing small diagnostic module or a focused small sibling if lint/size +requires it. No acceptance branch or native permission is introduced. + +_KimiFailureDiagnostic may retain this separately validated optional object only +for collector=single-tool,stage=approvals,phase=validate when the original observer +actually raises the new typed refusal. Preserve first retained cause; do not let +cleanup errors or a later unrelated phase acquire/replace it. Emit it only under +those same closed conditions, as an optional approval_poll_refusal field in the +existing <=2048byte failure line. Invalid internal optional facts fall back to +the existing generic failure; never replace or swallow the original exception. + +The observer still fails at exactly the same place. It does not catch the new +refusal as a graceful ResponseSchemaRefusal, call approve-once, fetch snapshot/ +history, call shutdown, start another process or expose quarantined raw data. +The existing ordinary supervisor determines actual failure cleanup and the +collector exit remains nonzero. This slice authorizes no new approval response, +remembered/blanket permission, native request, route, schema acceptance, polling +iteration, sleep, work/service/total budget, token, source/executable pin, hosted +guard, profile write, cache allowance, provider response or qualification. + +The exact native runtime failed-only ZIP schema/readers should need no change: +the diagnostic remains inside the existing stderr member. Verify that existing +closed admission still accepts original bytes unchanged. If an additional +schema consumer actually requires a change, identify its exact source contract +and return for review before expanding the plan. + +## Meaningful inert controls + +Use existing KimiAttemptContracts/CaptureContext/CaptureService and the actual +observer with the real ordinary supervisor around its existing inert Python +child. No Kimi, installer, provider model, scanner or managed launcher runs +locally; never fabricate hosted eligibility. + +1. Return two pending approvals on the first poll, including private canaries. + Require the same failed observer/quarantine behavior and nonzero failure, + finite multiple-pending/polls1 facts, no approve-once/snapshot/history, no + marker/tool call and no new native permission. Unknown row bodies stay absent + from the serialized diagnostic. Its whole line remains<=2048bytes. +2. Return an empty pending items list for all20polls. Exercise the exact existing + loop and its real bounds, require no-pending-after-polls/polls20, unchanged + failure/cleanup and no follow-on action. Do not increase sleeps or deadlines; + an inert sleep seam may only remove wall-clock delay while asserting20existing + sleep/poll operations, never alter production timing. +3. A single mismatched row still uses the existing single-row refusal facts; + response-shape failures retain their original dedicated graceful path. No + poll facts appear for successful single-row selection, unrelated stages, + component collector, malformed internal objects or another exception class. + Preserve all existing identity/permission/privacy/supervisor tests. +4. Strict object boundary tests reject bool counts,0/21/negative/float counts, + wrong/missing/extra fields, arbitrary/private reasons, wrong topic/status, + impossible exhausted count, nested/hostile objects and corrupted optional + facts. Verify returned maps do not alias held facts and original refusal + survives diagnostic failure. Check byte limit with existing optional fields. +5. Re-admit the unchanged genuine b2bb failed artifact through the exact new + source reader and compare all bodies/summary. It remains failed/incomplete/ + allfalse and does not acquire a fabricated reason retroactively. + +## Integration and publication + +Before coding, obtain two exact plan GOs and commit the accepted plan. Use an +isolated branch from agreed current Kimi source; no edits to the original +continuation checkouts. Prefer merging this reviewed disjoint Python slice with +the independently reviewed production scoped-selection fix before publication, +so one genuine hosted run can observe both independent boundaries. Reconcile +concurrent remote movement; never force, overwrite or substitute commits. + +Root coordinates actual serial focused and retained Python contracts/AST and +whitespace checks, and exact code review by two independent critics. The other +Kimi author owns the current Go/lint slot; no concurrent test-process suite +while that slot is active. Root alone publishes and updates PR524 after fresh +expected-head checks. A fresh genuine hosted capture and independent raw audit +must establish which refusal occurred, if either. It cannot turn the old failed +run into a pass or establish a full lifecycle, successful tool call, auth/model +qualification, main merge or release. diff --git a/docs/plans/project-install-e2e/kimi-scoped-selection-plan-review.md b/docs/plans/project-install-e2e/kimi-scoped-selection-plan-review.md new file mode 100644 index 000000000..8bdc50563 --- /dev/null +++ b/docs/plans/project-install-e2e/kimi-scoped-selection-plan-review.md @@ -0,0 +1,24 @@ +# Kimi scoped-selection plan approval + +The exact archived draft in kimi-scoped-selection-plan.md is approved before implementation. +The historical DRAFT header is retained to preserve the reviewed bytes. Plan SHA256: +`a9068b73fd29a8cad1bc6e0e6a79fc51f8d4b42e3841fb1cd618a346342299ef`. +Baseline: `b2bb2b7f85b5461420f932478b197905e6fc5ad9`, tree +`b12354b2565a05d14037556f8493b149d7d36ea2`. + +Two independent GPT-6.1 xhigh critics returned PRE-CODE GO on 2026-10-27: + +- R1 /root/scope_and_route_critic: review record SHA256 + `94230a717d9651f22bc51845c4005eeb0ce4233f119a3ae96a3be64be5080438`. +- R2 /root/native_current_review: review record SHA256 + `5b52e5e39c185863f3243b34908021773680d7e557248e4a63cf7e099276cc4b`. + +Both independently checked actual source/interface compatibility, wrong-layout +cause, explicit prior-binding scope and locator/digest authority, profile wrapper +forwarding, no fallback after scoped refusal, preserved old user API and damaged +artifact gates. Implementation must include actual intact composed public CLI and +Engine RED/GREEN regressions and the plan's refusal/compatibility controls. +Neither critic ran Go, lint, vendor processes or remote mutations. This approval +grants only the planned implementation; exact code reviews, executed gates, fresh +genuine hosted evidence and independent audit remain required. No native +qualification, merge, release or VS Code authorization follows from this record. diff --git a/docs/plans/project-install-e2e/kimi-scoped-selection-plan.md b/docs/plans/project-install-e2e/kimi-scoped-selection-plan.md new file mode 100644 index 000000000..f51866e49 --- /dev/null +++ b/docs/plans/project-install-e2e/kimi-scoped-selection-plan.md @@ -0,0 +1,224 @@ +# Kimi: preserve project MCP selection during intact repair + +Status: PRE-CODE DRAFT. This author has made no repository changes and run no Go, +lint, installer executable or vendor process. Obtain two independent plan reviews +and fix their findings before implementation. Root coordinates an isolated worktree +and the Go/lint slot; original checkouts and publication manifests remain untouched. +This draft is not a code GO, a native qualification or release authorization. + +## 1. Exact evidence and current source + +Read AGENTS.md, docs/PROJECT_INSTALL_OWNER_SCOPE.md, +docs/AUTHORING_CAPABILITY_PRESERVATION.md and the project completion plan. +Preserve useful user/legacy behavior. Active PR521–529 remain the scope; VS Code +is deferred and its dedicated source/tests must not change. No release. + +Starting Gemini-independent Kimi leaf: b2bb2b7f85b5461420f932478b197905e6fc5ad9, +tree b12354b2565a05d14037556f8493b149d7d36ea2. The original Kimi continuation +checkout was clean at that head during the source review. A narrow search found +no newer Kimi repair-selection plan, worktree or implementation. Recheck exact +head/clean status and coordinate with the current author before implementation; +never overwrite concurrent work. + +Genuine Kimi component run40569825577/job122438517506 failed after21.40s. +Native12767504412:14298 bytes, SHA256 +bb61975315455a478c3fc54083f23426c2c75b90be7f641132f98dbeac0e3af4, +40 closed ordinary members. Frontend12767812666:3519 bytes, SHA256 +06f000c1fc78c4546632cbb72d3b9d7704c06e4275538df2216e9d233082b075, +25 members. Independent audit: +/tmp/uap-kimi-b2bb-independent-20261027-uyq51c5q/audit.json, SHA256 +13138425fd8b44e166b3297882b04f023605b69dd00437b2cf6dde97800ea932. +Fresh API metadata, nested closed ZIP/CRC/ordinary membership, exact source/tree, +source/build cleanliness,24 frontend stream joins,4 nested service-stream joins, +37 HTTP joins and source-bound Python Kimi intake all pass. + +The repeated-add direct-result correction now advances: repeat-add-a and unchanged +update both complete without state/native-byte changes. Intact repair exits0 and +reports mutated=true, then the existing fixture correctly refuses with +“Kimi intact repair changed native bytes”. Its combined assertion checks the +selected skill OR project MCP file; after-repair bytes are not exported, so do +not claim to have directly read either changed file. + +Actual public result facts provide a separate concrete lead: add-a and unchanged +update classify the held MCP server as native. Intact repair keeps the same +installation/source tree/manifest/physical identity but changes that MCP component +to unsupported, reason not_in_recorded_delivery, and emits +managed_component_removal_planned. The old03d repeated-add parser defect is not +this failure. All five qualification, account/model flags remain false, and the +stable observation, later update/missing repair/removal/restart were not reached. +The separate Kimi single-tool lane supplies no qualification to this component lane. + +## 2. Source-proven scope/layout mismatch + +At exact b2bb: + +- clients/kimi/adapter.go ManagedMCPSelection always returns the user layout: + .kimi-plugin/plugin.json, nested mcpServers, with that member optional. +- clients/kimi/project_mcp.go projectKimiComponents writes the project delivery's + selected servers into the managed artifact's root mcp.json. It does not author + the user plugin manifest. Native .kimi-code/mcp.json is a separate projection; + read selection only from the verified managed artifact, never native mutable + configuration, a source package, or an unverified receipt claim. +- providers.Stager.ManagedMCPNames verifies the entire recorded artifact against + its held digest, dispatches the adapter's unscoped SelectionReader, reads that + one layout, then verifies the artifact again. Missing selection file yields + the existing nonnil empty selection. Therefore a valid project artifact is + read through the wrong user manifest layout and produces an empty selection. +- usecase.preflightTargetComponents uses that verified empty selection during + repair. restrictRepairMCPSelection then marks the project MCP unsupported with + the observed not_in_recorded_delivery reason; readiness/removal handling emits + the observed planned-removal diagnostic. + +This trace explains the observed removal plan. It is not a substitute for the +unexported post-repair byte observation. Preserve the current fixture refusal. +Do not add a formatting exception, semantic-only byte comparison or native-file +baseline adoption. + +## 3. Narrow additive scope-aware selection contract + +### Adapter policy + +Add one optional pure adapter interface next to SelectionReader, provisionally +ScopedSelectionReader with ManagedMCPSelectionForScope(domain.InstallScope) +(clients.SelectionLayout,error). It chooses a managed-artifact layout only; +it observes no filesystem, runs no process and adds no client capability. + +Kimi implements it with an explicit closed scope switch: + +- user: return the existing .kimi-plugin/plugin.json layout exactly, including + ServersMemberOptional=true; +- project: return root mcp.json, nested mcpServers, without optional member; +- unknown/empty scope: return an error, without guessing. + +Retain the existing ManagedMCPSelection method and its user API behavior exactly. +No choice based on file presence, directory spelling, detected ConfigRoot, +manifest contents, project-like paths or fallback to another candidate file. +A project skills-only artifact may still have no mcp.json and yield the existing +verified empty selection; a present dedicated document without mcpServers keeps +its existing refusal. User manifest omission semantics remain unchanged. + +### Provider and usecase propagation + +Add an explicit scoped Stager method, provisionally ManagedMCPNamesForScope(ctx, +clientID,scope,root,digest), while retaining ManagedMCPNames's existing signature +and behavior for existing direct/user callers. Both share the existing strict +artifact read implementation; preserve both complete digest verifications, error +behavior, fixed selection document parser and deterministic sorted names. +The new method validates scope, asks an adapter ScopedSelectionReader when present, +and otherwise uses the adapter's existing SelectionReader or generic default. +This fallback is for unchanged adapter policy; no generic client-ID table or +Kimi condition belongs in providers/usecase. + +In usecase, add a separate optional scoped managed-selection reader port. +recordedManagedMCPNames receives the already planned scope explicitly. Before +reading, require a known scope equal to the selected prior binding's scope; +retain exact target resolution/path verification and the prior managed digest. +Prefer the scoped port when present. The production providers.Stager implements +it, and profileStager forwards it after its existing original-profile check. + +Keep the legacy unscoped reader fallback for unchanged host stagers that implement +only the old optional port; do not remove their existing API or silently treat +that old port as absent. A wrapper must forward the scoped inner port when it +exists; it may not accidentally erase it and fall back. If a scoped reader returns +an error, propagate it: never retry unscoped or interpret that refusal as empty. +The production CLI/Engine/profile-wrapped Kimi paths must demonstrably reach the +scoped method. This correction makes no new scope-correctness claim for an +external host's custom legacy-only stager implementation. + +No staging, activation, repair selection restriction, native configuration +mutation, confirmation, version admission, data authority, scope authority or +state format is relaxed. Preserve the damaged/missing artifact route: names +from damaged bytes remain untrusted; the existing exact rebuilt-artifact digest +and ownership gates remain mandatory. This is not permission to resurrect +unrecorded MCP selection. + +### Compatibility alternatives and decision + +Changing the old exported ManagedMCPNames signature would unnecessarily break +existing direct consumers. Replacing Kimi's unscoped user layout globally would +break existing user registry semantics. Selecting whichever layout file exists +would infer scope from bytes and could confuse foreign/contradictory candidates. +A project-only registry adapter instance would leave Engine/SDK hosts that inject +the ordinary context-aware Kimi adapter inconsistent. The additive scoped port +carries the existing explicit authority through both composition paths while +retaining old contracts; its small forwarding surface is covered directly. + +## 4. Meaningful inert regression before native rerun + +Use existing fixture/composition helpers where their routes match. No native +vendor, scanner/installer binary, managed launcher or hosted-guard surrogate runs +locally. In-process Go filesystem/App/Engine execution is inert product testing, +not a native qualification. Do not replace the public repair path with a fake +result or hand-written native repair. + +1. Reproduce intact project repair through actual composed CLI App entrypoints: + independently author a local standard package containing skill plus MCP, + original user/A/B foreign settings and retained data, with inert detected + pinned Kimi and explicit failing-on-use native runner/launcher seams. Run + public project add, then public repair of the installed ID WITHOUT corrupting + managed/native/source bytes first. Before repair hold exact selected skill + and project MCP bytes and original user/B trees. Require the unchanged source, + installation, physical binding/data identities, project Prepared/Installed + state, selected MCP native support and ownership retained, no + not_in_recorded_delivery/removal diagnostic, and exact skill/MCP bytes after. + State/receipt evolution may reflect the real mutated repair; do not assert a + fictitious no-op classification. This regression must fail against b2bb's + original implementation and pass only with the scoped correction. +2. Exercise the same intact repair using the actual public Engine/SDK composition + with a directly injected ordinary Kimi adapter. Preserve the existing corrupt + or missing old-pin repair test separately: that damaged-byte fallback did not + cover this intact verified-artifact case. Prove original user/B/data isolation + and run no native process. +3. Through the actual Stager, stage/verify project and user artifacts and read + their recorded selections using explicit scopes. Project selection must use + root mcp.json; user and the old unscoped API must use the original manifest. + A bounded independently authored digest-verified artifact with conflicting + candidate files proves the selected layout is authoritative and no fallback + occurs. Skills-only user/project cases retain their intended empty selection. + A malformed selected dedicated document refuses even if another candidate is + well formed. Unsupported scope errors must occur before interpretation. +4. Verify both artifact-digest checks and no damaged-byte selection. Altered + managed bytes or mismatched held digest refuse selection; wrong scope/prior + binding/target locator refuses at the usecase authority boundary. Foreign + native namespace collisions or changed managed native objects retain existing + refusal and no target mutation. The ordinary safe repair of damaged owned + bytes still requires its existing exact reconstruction/ownership conditions. +5. Add focused forwarding contracts for profileStager and scoped-versus-legacy + stagers: exact held scope reaches the new port, original profile failure + prevents the read, scoped errors never fall back, legacy user behavior is + retained, and adapters without scoped policy retain their previous layout. + Do not add generic client-ID cases or grow architecture allowlists/baselines. + +The existing native byte-stability assertion at intact repair remains unchanged. +Run the regression RED on the original source via inert overlay or isolated +checkout, then GREEN on the final exact code. Do not edit original native evidence +or execute the full opt-in native fixture locally. + +## 5. Files, review and gates + +Expected product files: clients/identity.go; Kimi adapter-owned selection method; +providers/managed_selection.go; usecase/managed_selection.go and native_binding.go. +Use small new focused provider/usecase/Kimi contracts and a real composed CLI +regression plus a public Engine regression, extending existing fixtures rather +than introducing a second installer. Preserve all existing tests and useful +legacy source. No dedicated VS Code file, global client registry policy, shared +native parser, native collector, qualification flag, Python evidence schema, +provider credential, runtime pin, timeout, artifact member or production state +format needs to change. + +After two independent exact plan GOs, root supplies an isolated branch at the +fresh agreed source. Commit the accepted plan before implementation. Obtain two +independent exact-code reviews, fix findings and retain incremental commits. +Root coordinates focused existing/new Kimi public lifecycle/provider/usecase/ +selection tests, relevant default-adapter compatibility contracts, all-enabled +affected lint, the unfiltered whole-file architecture/size lint gate, gofmt and +whitespace. Attribute actual test commands/results to their executor. Do not run +concurrent Go/lint or repeat optional gates without a remaining concrete risk. + +Root alone performs fresh expected-head publication to the existing Kimi PR, +without force or overwriting concurrent source. If another author has moved the +leaf, preserve/reconcile/review their exact combined bytes first. A new genuine +hosted component run and independent raw audit must establish native consequences. +The separate single-tool approval/history boundaries remain independent. No old +failed capture becomes successful, no qualification is inherited, and no merge, +release or VS Code authorization follows from this plan. diff --git a/docs/plans/project-install-e2e/qoder-auth-membership-addendum-plan.md b/docs/plans/project-install-e2e/qoder-auth-membership-addendum-plan.md new file mode 100644 index 000000000..7bfd34e26 --- /dev/null +++ b/docs/plans/project-install-e2e/qoder-auth-membership-addendum-plan.md @@ -0,0 +1,81 @@ +# Qoder anonymous metadata: exact auth-directory membership + +Status: proposed correction; no code in this slice has been changed. This addendum +responds to two independent reviews performed after the original metadata recipe +was implemented. It does not backdate those reviews into preimplementation GOs. + +## Frozen starting point and concrete defect + +Start from candidate 39f1267d5096a0f8c2e3cd0388e047978c2c7de6, tree +9e452cff096e0ab53b3cdf235258a4a2ddc9dd30, in a separate worktree. Preserve the +existing author's complete commits and contracts. The helper currently has SHA256 +be18f86af7d290b079d5b360c85b501e8451969a47005761fe8ad6455c9ea7f7; +contracts b2799da43d86c5ee961ba8eba0aec3f584155ec30914cae47e0cf6c6eb74736e; +shared fixture 557b178c29b065ba5e17a55b42ae3e1c3c77dce3402a5199e9ed4eb00110359e. + +The current fixed-file checks do not enumerate .auth. setup runs native version +and public add before the first complete-profile catalog snapshot. Consequently +an unknown .auth sibling can pass recipe.check and enter that later baseline. +This is a source counterexample, not observed native account creation. + +## Narrow implementation + +Add a private bounded verifier for the exact direct .auth names machine_id and +.credential-transaction, and no others. Do not enumerate the whole profile or +read unknown child bodies. Open a readable directory descriptor relative to the +already-held .auth descriptor with openat(".", O_RDONLY|O_DIRECTORY|O_NOFOLLOW| +O_CLOEXEC); never reopen an unchecked filesystem path or use O_PATH for readdir. +Check held ownership, directory type, exact0700 and identity against the captured +auth directory before and after enumeration. Use a fresh descriptor each call, +read at most three entry names, and require exactly the two expected unique names +and EOF, with all read and close errors refusing. Unknown names are not printed. +Keep existing fixed-file regular-file, owner, mode, size, link, identity and digest +checks; expected names still pass those independent checks, so no special file, +alias or changed expected child gains authority. + +Enforce membership from initial capture onward and around every existing recipe +check, including the final linked identity phase. Preserve held profile/auth +checks and linked Fstatat verification before/after the membership operation. +Do not pin directory access timestamps across commands; ordinary reads and +same-mode chmod retain their existing semantics. Inside a single enumeration, +verify stable directory identity and membership-relevant metadata to refuse a +concurrent mutation; any observed change is a refusal, never a new baseline. +Retain the full original-profile equality guard and all command boundaries. + +No changes to production adapters, vendor pins/argv, original HOME, credential or +trust handling, file contents, deadlines, cleanup, parser allowances, qualification +flags or VS Code. No native/vendor executable will run locally. The recipe still +does not establish equivalence between the public npm source and the pinned +standalone executable, or account authentication or successful native behavior. + +## Regression and validation + +Add actual recipe.check controls before any complete-profile snapshot: create +.auth/user, .auth/user.production or an unrelated sibling as an ordinary file; +also exercise a directory, symlink and FIFO without opening their bodies. Each +must refuse promptly, leave the unknown object and the authored bytes intact, +and keep the fixed-file protections. Add direct initial-capture rejection with +an unknown entry and repeated positive checks, including after ordinary reads and +same-mode chmod. Preserve every prior test. No mock positive native result. + +Run the new direct regression against the old helper using an inert Go overlay +to show the concrete gap (expected failing test), then the corrected focused +Qoder/shared inert Go contracts and actual affected all-enabled plus unfiltered +whole-file architecture/size lint gates. Serialize Go/lint with any active job; +do not delete another task's files. Use two independent plan GOs before coding and +two independent exact-code reviews after the correction. Record source hashes, +actual commands/results and their scope without attributing other workers' test +execution to this worker. + +## Publication and concurrency + +Do not edit /tmp/uap-qoder-publish or its publication manifest/checkpoint. Commit +this addendum, correction and actual validation separately in the isolated branch. +Publish only after fresh inspection of the existing PR523 head, full source review +and checks. A normal fast-forward may include the original author's39f126 ancestry; +if concurrent source differs, stop publication, preserve it and reconcile/review +the exact combined bytes. No force-push, replacement PR, merge of unqualified leaf, +release, cancellation of unrelated CI or change to the original negative captures. + +All existing five qualification flags remain false until genuine current-source +hosted evidence independently establishes applicable claims. diff --git a/docs/plans/project-install-e2e/qoder-auth-membership-plan-review.md b/docs/plans/project-install-e2e/qoder-auth-membership-plan-review.md new file mode 100644 index 000000000..bff4473d6 --- /dev/null +++ b/docs/plans/project-install-e2e/qoder-auth-membership-plan-review.md @@ -0,0 +1,16 @@ +# Qoder auth-membership addendum: preimplementation review + +Plan SHA256: `ff0d090da140c389e0690990ab6cd7440b8c1f2c92c008f2f28bb64fb0ff2b3f`. + +Starting commit: `39f1267d5096a0f8c2e3cd0388e047978c2c7de6`. + +Before correction code was changed, two independent GPT-6.1 Sol xhigh reviewers +read the exact plan and starting source. `kimi_current_review` returned R1 GO, +and `native_current_review` returned R2 GO, without required plan corrections. +Both confirmed the bounded readable descriptor anchored to the held auth +directory, exact two-name set and EOF, initial and repeated checks, unchanged +fixed-file protections, and direct prebaseline hostile controls. + +These approvals apply only to this membership correction. They do not backdate +reviews of the original metadata implementation and do not establish a native +pass, account authentication, MCP capability, model use or release qualification. diff --git a/docs/plans/project-install-e2e/qoder-auth-membership-validation.md b/docs/plans/project-install-e2e/qoder-auth-membership-validation.md new file mode 100644 index 000000000..d6aa616f8 --- /dev/null +++ b/docs/plans/project-install-e2e/qoder-auth-membership-validation.md @@ -0,0 +1,63 @@ +# Qoder exact auth-membership correction: validation + +## Reviewed source and chronology + +The membership addendum was approved before its implementation by independent +GPT-6.1 Sol xhigh reviewers `kimi_current_review` (R1) and +`native_current_review` (R2), at exact plan SHA256 +`ff0d090da140c389e0690990ab6cd7440b8c1f2c92c008f2f28bb64fb0ff2b3f`. +The plan and review record were committed as `2b63d444f9cbb25be9fa23a475e80e50e0a5b22a`. + +The correction was committed as `b42ff698deb486b69b611b9d2adb6ead6accebb9`. +Both independent reviewers read the complete helper, contracts and wiring and +returned exact-source CODE GO. Actual lint then identified one staticcheck QF1001 +finding. Commit `83dd06d0bc3e932baf4f8de3d59333f167898e08` changes only the two +predicate lines using De Morgan's law. Both reviewers read that exact delta and +extended their CODE GO. Final code tree: +`c25f4a711379822b835b3e1e18f0bd6624cbcea4`. + +The original metadata author's complete `39f1267d` history and tests remain +preserved. This correction's plan approvals do not backdate reviews of that +original implementation. + +## Actual inert validation + +The new direct regression was run against the original helper through a Go +source overlay. It failed as expected for all six unknown auth siblings and for +initial capture, demonstrating the early-baseline gap. It ran in 0.013 seconds +of package test time. The old helper was never installed over the working source. + +On the final corrected source, the following gates actually passed: + +- `go test -p=1 -count=1 -timeout=120s ./repotests -run '^(TestQoder|TestProjectNativeCLI)'`: + PASS, 0.049 seconds of package test time. +- All enabled lint on the affected delta from `39f1267d`: zero issues. +- Unfiltered whole-repotests `revive,funlen,gocyclo,gocognit,dupl,depguard`: + zero issues. +- Formatting and whitespace checks: clean. + +Go 1.26.10 and golangci-lint 2.13.2 ran with offline dependency resolution. No +vendor executable, hosted environment simulation or native qualification ran +locally. The reviewers' static code approvals are separate from these root-run +tests. + +| Actual log | SHA256 | +| --- | --- | +| Original helper counterexample | `564c195467b4282a497b9c9a4aa0c39c01cae30f4f9d68c4a5f721642dac7d5d` | +| Final focused Go | `0df67033922854846ec5ae3c86b30b637afb41defd26348a039098ec250430c9` | +| Final affected lint | `e92606b0bf483111dff0a120c315ea165821348f31365020e2468a0059095c47` | +| Final unfiltered six-linter gate | `e92606b0bf483111dff0a120c315ea165821348f31365020e2468a0059095c47` | + +## Preserved evidence limits + +The fixture now rejects any direct `.auth` entry other than `machine_id` and +`.credential-transaction`, including before the first full-profile snapshot. +It enumerates bounded names through held directory authority and never reads +unknown bodies. Existing file ownership, byte, mode, inode, link, directory and +full-profile checks remain required. + +This is a fixture acceptance correction. All five qualification flags remain +false until genuine, current-source hosted evidence establishes applicable +claims. The earlier negative captures, their omissions and the absence of account +or model qualification remain unchanged. No new MCP support, VS Code work, merge +of an unqualified leaf, release or vendor-binary/source equivalence is claimed. diff --git a/docs/plans/project-install-e2e/qoder-empty-telemetry-directories-plan-review.md b/docs/plans/project-install-e2e/qoder-empty-telemetry-directories-plan-review.md new file mode 100644 index 000000000..d1ee007fc --- /dev/null +++ b/docs/plans/project-install-e2e/qoder-empty-telemetry-directories-plan-review.md @@ -0,0 +1,18 @@ +# Qoder empty telemetry directories: preimplementation review + +Exact reviewed plan SHA256: `27a91ec4a8dcff76d08eabb2363701feeb20f73a4ce7a4c12e108db746d14256`. +The retained plan is the original frozen draft; both decisions below approve +that exact text before implementation. + +Independent GPT-6.1 Sol xhigh reviewers `native_finish` (R1) and +`kimi_cline_finish` (R2) returned GO. Both independently checked the pinned +official npm archive and bundle, the three corrected UTF-8 byte spans and +the three literal path hashes. They reviewed exclusive creation, exact +0700/current-owner held ancestry, closed membership from the first child, +within-check stability and no timestamp pin across commands. + +The current genuine 89321cbe capture remains failed/unqualified. Source supports +the three-directory fixture recipe, not shipping binary/source equivalence or +any unexported marker value. Four omitted log details remain unproved; the +complete profile, auth membership, original IDs/settings and logging guards +are unchanged. No vendor or public installer was run for either review. diff --git a/docs/plans/project-install-e2e/qoder-empty-telemetry-directories-plan.md b/docs/plans/project-install-e2e/qoder-empty-telemetry-directories-plan.md new file mode 100644 index 000000000..dbb6a201c --- /dev/null +++ b/docs/plans/project-install-e2e/qoder-empty-telemetry-directories-plan.md @@ -0,0 +1,93 @@ +# Qoder: independently authored empty telemetry directories + +DRAFT, not an implementation approval. Start from current published +89321cbe5baf79d5837da4ad95040beabcd6cdbc/tree +f75668e2162758f31327e6140e4ec4b355350813. Preserve the complete metadata and +exact-auth-membership corrections and their historical evidence. + +## New measured boundary and public source + +Genuine runtime40575301213/job122446553803 retains native12768990209 and +frontend12766634473. Root independently verified both API sizes/digests, closed +16/25 members, 24 frontend stream joins, exact committed source/tree and current +failed-only admission. Public add and the actual native catalog both exit0. +The catalog identifies the one expected enabled @flag installed plugin view. +The original anonymous metadata and exact .auth checks pass. The complete +original-profile guard still fails:12 to18 entries,6 added,1 changed,4 omitted. +All five/runtime/account/model flags remain false; no native session ran. + +All three exposed added directories have mode0700. Their recorded path digests +match exactly the following public-source literals/compositions: + +- tmp: cf10d3eb4b80f1fdd74306ab6e6152f1822b19451b959eba448ba2d0b2beb22b. +- tmp/telemetry: 9e364e7b404f8f44485dabd0a69b74fa7f7c92a8e2c6adac0650e765164cf7c7. +- tmp/telemetry/active-runs: 8aae50c2aa8f464951f142637714289606a7b6e289dce8c85e9257aaef9998c6. + +Pinned official npm1.1.78 archive SHA256c5b237d2fd84ceb44af5427f281a7f1bcadd8c888fbed49197b5ce2f37dada4f +contains bundle/qodercli.js SHA256ec7b2a2c1be206f525ca974c3b9455fbec9ce7411bc5dfdee55f1e82eb90df38. +The source's abnormal-exit marker defaults to join(globalProfile,tmp,telemetry, +active-runs), creates it recursively with mode0700, and removes its own marker +on completion. Source spans and exact literal joins are recorded in +/tmp/uap-qoder-893-root-audit/source-research.json, +SHA256beba66984e341b9b4d78207b85b228df1e678f7bcb316a51a6ec46f8a6b4ffe5. +The standalone binary/source correspondence remains unproven. No captured +private identifiers or file contents were read or inferred. + +Four log/latest details remain omitted. Source logger layout suggests a new +per-process run directory, qodercli.log, manifest.json and latest link, but their +actual omitted path/body details are unobserved. This slice grants NO logging +exception and cannot claim that the complete profile guard will pass afterward. + +## Exact original fixture recipe + +Before the first existing child in the genuine Qoder constructor, create only +these three new ordinary directories inside its original disposable .qoder. +Require every target initially absent; create exclusively through held no-follow +parent authority, set exact0700 only on newly created held descriptors, and +verify current UID/GID, ordinary-directory type and linked identities. Do not +reuse a preexisting directory, symlink, alias, foreign target or inherited tree. +No marker file, ID, account record, log, credential or trust value is authored. + +Retain a private recipe for the three initial device/inode/UID/GID/full modes. +Check it before and after every existing selected command, alongside the current +metadata/auth checks. Use fresh readable descriptors anchored to held directory +handles for bounded exact membership: tmp has only telemetry, telemetry has +only active-runs, and active-runs is empty. Read at most expected-count+1 names, +require exact unique names and EOF, and refuse read/close errors, unknown +children/types/links, parent substitution or ownership/mode drift. Do not open +unknown child bodies. Expected child directories retain their independently +held identity; the final linked checks must not accept a replacement chain. + +Within one check require stable held/linked metadata across enumeration. +Between commands do not pin directory access/change/modification timestamps: +the real source may create and remove its own temporary marker before returning. +The final exact empty-member check supplies the boundary. A leftover marker or +any other residual child remains a failure, never a new accepted baseline. + +Preserve the existing whole-profile before/after equality guard with no excluded +prefix, adopted map, rewritten baseline or logging allowance. Preserve exact +settings/anonymous-file bytes and modes and the closed .auth membership check. +No client argv/env/config behavior, telemetry switch, profile redirection, +provider/authentication path, acquisition/scanner/executable/source pin, +process/cleanup/deadline, raw schema, success admission or qualification changes. +No VS Code work or release. Any newly revealed profile difference remains an +actual failed observation for separate review. + +## Meaningful verification and publication + +Use ordinary inert files/directories to prove exclusive creation, exact modes +and full ancestry identities; required exact membership before any later profile +baseline; unknown child at each of the three levels; aliases/special entries; +early chmod and same-name parent replacement preserving all child inodes; and +changed original settings/ID/auth protections. Repeated valid checks and a +create-then-remove inert marker must pass while a retained marker refuses. +Keep all existing Qoder tests. No vendor, public installer or positive hosted +simulation runs locally. Do not claim the inert marker is native telemetry. + +Two independent plan GOs precede code. Use a new isolated exact-current-head +branch, independent exact-code review, focused Qoder/shared contracts and current +negative raw replay, actual all-enabled affected root lint and unchanged whole- +root six-linter gates. Coordinate the Go/lint slot and preserve every prior +capture. Root alone publishes a normal fast-forward after fresh remote/base +inspection; concurrent changes are preserved and reviewed, never overwritten. +The subsequent genuine capture establishes only its actual next boundary. diff --git a/docs/plans/project-install-e2e/qoder-empty-telemetry-directories-validation.md b/docs/plans/project-install-e2e/qoder-empty-telemetry-directories-validation.md new file mode 100644 index 000000000..973439f66 --- /dev/null +++ b/docs/plans/project-install-e2e/qoder-empty-telemetry-directories-validation.md @@ -0,0 +1,63 @@ +# Qoder empty telemetry directory validation + +This slice starts from published +`89321cbe5baf79d5837da4ad95040beabcd6cdbc` and implements only the +[independently reviewed directory recipe](qoder-empty-telemetry-directories-plan.md). +Native R1 and Kimi R2 approved exact plan SHA256 +`27a91ec4a8dcff76d08eabb2363701feeb20f73a4ce7a4c12e108db746d14256` +before the separate plan commit `7389fc66b0fc7ffcff78e77900a2571e3c70a5f7` +and implementation. Root authored the code; native independently reviewed all +three changed code files and gave CODE GO on tree +`f5918dd2910d8f3bb1cb8a4970c5eb76d61478d3`. + +The original constructor now exclusively creates `tmp/telemetry/active-runs` +under its original disposable `.qoder`, with exact mode0700 and held ancestry +identities. Every existing command retains the original context, profile, +anonymous metadata and closed auth checks and additionally checks the exact +three directory identities and closed membership. The final directory is empty. +No unknown child body is opened. A leftover marker, substituted parent, +permission drift or unknown child refuses. Directory timestamps are stable +within each check; they are not adopted as an across-command identity rule. +The complete existing profile equality and logging guard remain unchanged. +No logging exception or native account/permission/trust value was added. + +## Actual local verification + +- Focused inert `go test ./repotests -run '^(TestQoder|TestProjectNativeCLI)' + -count=1` passed, package0.112s and wall10.673s, on reviewed treef5918. +- Actual all-configured full-root affected lint against + `a412ba5e137fdcb7e004393229b323211ed746e1` initially found one spelling issue + in a new assertion message: `cancelled` instead of `canceled`. The failed + gate output is retained. Only that literal changed; native independently + confirmed the exact one-line delta and gave amended CODE GO on tree + `8df29edea8545365cd8964161e266ea982637c83`. +- Actual all-configured full-root affected lint on the amended tree reported + zero issues in31.631s. The unchanged whole-root + `revive,funlen,gocyclo,gocognit,dupl,depguard` gate reported zero issues + in1.625s. No lint exclusion or suppressed finding was introduced. +- Gofmt and staged whitespace checks passed. The sole post-test spelling + correction changes no executable predicate, fixture behavior or assertion. +- The genuine source893 native artifact12768990209 was replayed through the + current strict reader. Its inner ZIP SHA256 is + `764c0de8ac7c11399278f46ea684b2d0c2078cae55635994276af59d2403e0c7`. + All16 closed members remain accepted only as the original failed, + incomplete observation, with all five, account and model flags false. + Both runtime and shared research reader bytes are identical to source893. + +The implementation commit is +`9b2a946ff95960a09067def78abebb98941e4074`, with exact reviewed tree8df29. +Local receipts are retained as `/tmp/uap-qoder-empty-telemetry-focused-go.json`, +`/tmp/uap-qoder-empty-telemetry-lint-gates.json`, +`/tmp/uap-qoder-empty-telemetry-lint-gates-v2.json` and +`/tmp/uap-qoder-empty-telemetry-current-raw-replay.json`, with their corresponding +full command logs and hashes. This record adds no code after review. + +## Remaining genuine boundary + +The previous actual native catalog succeeded but the original full-profile +check failed on three new telemetry directories plus four omitted logging +details. This slice does not infer or authorize those omitted details. A new +genuine hosted capture must establish its actual next boundary. No vendor, +public installer or scanner executed locally; no hosted environment was +simulated. Native session, MCP operation, complete lifecycle, account and model +qualification remain unproved. This slice authorizes no merge or release. diff --git a/docs/plans/project-install-e2e/qoder-file-profile-delta-priority-plan.md b/docs/plans/project-install-e2e/qoder-file-profile-delta-priority-plan.md new file mode 100644 index 000000000..2c3114693 --- /dev/null +++ b/docs/plans/project-install-e2e/qoder-file-profile-delta-priority-plan.md @@ -0,0 +1,76 @@ +# Qoder: prioritize held file changes within the same bounded diagnostic + +## Source-bound observation and passive source research + +PR523 source faf2fef5ae4c094698b6818b4b6380f11b0bd351 has tree +ed31f769953b661d46975078dfd5d29cb782c540, equal to the surviving local +48a11189bdb00e19283d653679df44fafe149d05 tree. Genuine runtime40495061122, +native job122168330253, produced artifact12732771926 with verified SHA256 +f52ca8dd0a55104125fee2c9e94bd90bcdbd0267fc8d6510adacd9cbc0aa254e. +The native catalog exited0 without diagnostics. The complete original-profile +comparison still refused ten additions and one change: logs3, latest-link1, +other7, with zero settings/plugin/cache area changes. Only three other +details fit: two0700 directories and one36-byte0644 ordinary file. Eight +details remain omitted; no ordinary startup command or qualification follows. + +Current publisher documentation preserves original ~/.qoder authority and +describes user settings/authentication/plugins, but does not establish every +observed path or authorize native writes. Official installation documentation +retains the npm compatibility package. Passive reading of the publisher's +exact @qoder-ai/qodercli1.1.78 npm archive verified its published SHA512 +integrity and SHA1; archive SHA256 is +c5b237d2fd84ceb44af5427f281a7f1bcadd8c888fbed49197b5ce2f37dada4f; +bundle/qodercli.js SHA256 is +ec7b2a2c1be206f525ca974c3b9455fbec9ce7411bc5dfdee55f1e82eb90df38. +Its public installation_id and .auth literals cryptographically match two +observed key hashes. Source-defined .auth/machine_id is a concrete future +comparison. The actual identifier value and remaining paths are unknown. +The npm source is not proof of standalone executable code identity. No +package, postinstall hook, JavaScript bundle or vendor client was executed. + +Sources checked2026-10-27: https://docs.qoder.com/cli/installation, +https://docs.qoder.com/cli/settings, https://docs.qoder.com/cli/config-scope, +https://registry.npmjs.org/@qoder-ai/qodercli/1.1.78 and its dist.tarball. +This evidence does not justify preauthoring/adopting identity or authentication +files, permitting logs, redirecting HOME, or renewing the preservation baseline. + +## Minimal pure ordering amendment after two independent plan GOs + +Change only qoderDeltaPriorityLess in the existing priority helper/contracts +file and add one bounded Linux contract file, plus this accepted record. +Keep the existing other-area-first rule. Within that area only, prefer an +entry if either already parsed Before.Kind or After.Kind is file. This covers +added, removed and type-changed regular files without losing those events. +Then retain the existing key-SHA256 order. Directory-only other entries remain +in their original relative order. All known-area ordering is unchanged; with +no other changes, or no mix of file/non-file other changes, selection remains +byte-identical. A file classification is observation only, never permission. + +Preserve every count/area/record/parser rule, 4096-map/8192-union bounds, +three-detail limit, exact omissions/status and complete2KiB bound. Add no JSON +field, raw path/body/target/error, filesystem read, native command, environment +variable, account operation, parser, deadline or admission/qualification rule. +The unchanged complete before/after comparison and fatal remain authoritative. +Never replace the held maps or exempt a mutation based on the diagnostic. + +## Meaningful inert verification and next genuine boundary + +Use real owned profiles to reproduce seven other additions comprising two +directories and five files plus the existing log/latest changes. Independently +state the selected file key hashes and file metadata, exact ten additions/one +change/three details/eight omissions, privacy and complete serialization bound. +Cover removed-file and file/directory replacement classification, all-directory +and all-file preservation of prior ordering, reverse map insertion order and +returned-projection/input non-aliasing. Retain the existing no-other/one-other, +malformed/bound/rotation/held-profile controls; compare filesystem bytes and +metadata before/after projection to prove no diagnostic mutation/adoption. + +Run focused existing/new Qoder, log-link and shared CLI inert contracts plus +actual all-enabled affected-line and unfiltered whole-file size/architecture +lint in an exclusive Go slot. Obtain independent exact-file code review. +Root alone publishes to existing PR523 after a fresh expected-head check. +The next genuine capture may expose additional file hashes for source-backed +identification; remaining omissions are still explicit and may need further +diagnosis. No current or future hash match alone establishes allowed writes, +complete preservation, native selection, authentication or lifecycle/MCP +qualification. All existing false flags and release/merge gates remain intact. diff --git a/docs/plans/project-install-e2e/qoder-file-profile-delta-priority-validation.md b/docs/plans/project-install-e2e/qoder-file-profile-delta-priority-validation.md new file mode 100644 index 000000000..63182f60a --- /dev/null +++ b/docs/plans/project-install-e2e/qoder-file-profile-delta-priority-validation.md @@ -0,0 +1,53 @@ +# Qoder held-file detail priority: exact validation + +## Reviewed source boundary + +The published base is PR523 head +`faf2fef5ae4c094698b6818b4b6380f11b0bd351`, tree +`ed31f769953b661d46975078dfd5d29cb782c540`. Plan commit +`81bb84d11bd73e459ec16adbe57972c0dad1c1e4` preserves the exact independently +approved plan SHA256 +`69031dd2cfaaf9fb72706f33c4e6783d22d6e7dddb0f0fe3e5fa56cd3793c2a2`. +Root gave R1 GO and CLI gave independent R2 GO before source edits. + +Code commit `9b2f5466c3b4a4a401229c31cd343894e751922b` has reviewed tree +`1ca241e5d2218d7547136c83b08f9d1d97ac9e0c`. Only two code files changed: +the existing comparator has seven added lines and the new inert contract file +has 140 lines. Their SHA256 values are +`87f80a281af6f760c30f38d1e08847841785f829039c06c1fcfc3568d174588f` +and `5b8fbe1add6cf9f3db9166f54206f37749a93608f1f97aa6ab72dcf8e3ee40f0`. + +CLI independently read the complete two-file delta and existing bounded +inventory/parser/fatal contracts, reconstructed the fixed expected key/content +hashes in Python, and gave exact-tree CODE GO without findings. Root separately +reviewed the comparator and approved the same tree. No source changes followed +these reviews; this record does not alter reviewed code. + +## Actual verification + +Focused inert `^(TestQoder|TestProjectNativeCLI)` contracts passed in 0.157 +seconds with Go 1.26.10. The actual all-enabled affected-line root lint gate +against plan commit `81bb84d1` reported zero issues. The unchanged unfiltered +whole-root revive/funlen/gocyclo/gocognit/dupl/depguard gate also reported zero +issues. Gofmt and staged whitespace checks are clean. + +Real-file controls cover two directory and five file additions with the +measured log/latest shape, exact ten-addition/one-change counts, three selected +details and eight omissions. Removed files and both file/directory replacement +directions retain file priority; all-directory, existing all-file and known-area +ordering remain strict. Independent literal hashes, reverse map insertion, +before/after pointer non-aliasing, private serialization and full actual profile +metadata frames are checked without adopting the unequal before/after maps. + +The current genuine native artifact `12732771926`, from run `40495061122`, +has verified outer SHA256 +`f52ca8dd0a55104125fee2c9e94bd90bcdbd0267fc8d6510adacd9cbc0aa254e`. +Its actual sixteen-member archive replays through current admission unchanged +as failed/incomplete, with all five qualifications false and eight omissions. +No omitted path, body or authentication state is inferred from that replay. + +No vendor, package hook, public installer or positive hosted guard ran locally. +The diagnostic adds no read, field, permission, baseline renewal or preservation +exception. Root alone owns publication and fresh genuine capture review. The +complete original-profile mismatch remains fatal; lifecycle, MCP, account, +model, merge and release gates remain unchanged. diff --git a/docs/plans/project-install-e2e/qoder-original-profile-delta-plan.md b/docs/plans/project-install-e2e/qoder-original-profile-delta-plan.md new file mode 100644 index 000000000..d54ec3649 --- /dev/null +++ b/docs/plans/project-install-e2e/qoder-original-profile-delta-plan.md @@ -0,0 +1,152 @@ +# Qoder catalog: measure the refused original-profile delta + +## Exact new genuine observation + +Start from published PR523 `ccd9dc9e12724b43bae001b3d3573d95c7994297`, +tree `ac550cf4f510b86b3f0405434a207d05883cbb5d`, identical to reviewed local +`213500c02df3b2cb06ff4339007633090a01d5d9`. A fresh actual git-ref read +still returned that source. Preserve the separate local lifecycle-design branch +and every prior plan/code/native capture. This is a new diagnostic-only slice. + +Genuine run `40459286447`, native job `122045321108`, passed hosted clean-source +admission and the new original-log-link checks. The original observed link has +42 target bytes, original UID/GID1001, nlink1 and a contained ordinary owned +directory target. The helper admitted that structure without following the +link; its exact target text stayed private. This is actual structural evidence, +not proof of a native project registry or safe future log mutation. + +Public add-a exited0/error=false/deadline=false in564ms. Native catalog then +exited0/error=false/deadline=false in1135ms, stderr0. Its766-byte stdout SHA256 +is `a07f47c35d5069aa7ed09e144c0d52a399e4381c991751af9bc7068161daea45`. +The actual strict JSON is a single flag-scoped row with exact name/version, +id `uap-qoder-attempt@flag`, source `uap-qoder-attempt@inline`, enabled=true, +canDisable=false and the exact receipt-selected native-view installPath. It +describes the one authored skill and empty agents/MCP/commands/hooks arrays. +Those are observed catalog fields, not a new approved runtime parser, loaded +skill-body proof, trust grant, MCP exchange or authenticated model result. + +The second complete original-profile inventory succeeded structurally, then +the existing exact before/after map comparison failed: +`Qoder catalog changed the complete original user profile/cache`. +Startup did not run. The capture does not identify which entries changed or +whether it was log content, link rotation, new files, registry/cache or settings. +Do not claim ordinary logging as the captured cause or waive any profile entry. + +Native12714971725 outer SHA256 +`162c5d94d7556e982a6433d1a1a93ad897382fb66b4d3ccc1dcbea021cb66c91`, +inner `296c4c9a3e900f9bc213f448486756d7588f247f438ecd0416327224233da9d5`, +has16 members. Frontend12714273659 outer +`a53edb7f7eee4edc72a00c90268389d107585d5fdac2c8a6d18f2ce0e44e4f8c`, +inner `41e23e9a74341b8290a3a195817f23fe86e836f6d7d15108d02c229bc0138de6`, +has25. API sizes/hashes, bounded canonical unique ordinary ZIP closure/CRCs, +exact committed source/tree/empty patch list, clean-source streams and all24 +frontend command-stream hashes were independently checked. All five native +qualifications, vendor authentication and real-model flags remain false. + +## Narrow held-map diagnostic after two independent plan GOs + +Scope: the existing shared CLI-attempt file's exact unequal-profile-map branch, +one new private Linux Qoder delta helper/contracts file, and this plan/validation +record. Do not change inventories, target acceptance, native args/cwd, reads, +budgets, original user authority, catalog JSON acceptance, pins or other clients. + +Immediately before its unchanged fatal, add a small optional original-profile +delta object to the existing runtime summary, derived ONLY from the two already +accepted complete inventory maps. No filesystem root is passed to the formatter; +it performs no read/stat/readlink/open, recursion, follow, repair or baseline +renewal. Only this post-catalog unequal-map branch uses it. An inventory error +continues to fail through its existing path without this projection. + +The finite schema reports status, before/after entry counts, exact totals for +added/removed/changed entries and fixed area counts. Areas are exact logs/latest +(`log-latest`), other descendants of logs (`logs`), exact settings.json +(`settings`), plugins/cache and its descendants (`plugin-cache`), other plugins +entries (`plugins`), cache and its descendants (`cache`), and everything else +(`other`). Area is only a static category; it confers no mutation permission. +Every changed entry contributes to the counts, including directories and links. + +At most three deterministic changed-entry details may be included. Select them +by the fixed area order above and then SHA256 of exact relative-key bytes; +never use raw names as serialized keys or expose their ordering/text. Each +detail has only that key SHA256, static area, added/removed/changed operation +and finite before/after metadata. The two input maps remain byte-identical. +An explicit omitted_count/status distinguishes a larger delta from a complete +three-entry report. It is a bounded diagnostic, never an alternate proof that +unreported changes are harmless. Input maps remain subject to the existing +4096-entry inventory cap; reject an oversized synthetic input rather than +processing an unbounded union. A union is therefore at most8192 keys. + +Metadata contains only absent/directory/file/symlink kind, existing numeric mode +and file byte count where present, and the existing file-content SHA256. For the +special link record, expose only a SHA256 of its existing complete numeric/ +target-digest record, not its raw record or target text. This retains a signal +for same-target inode/timestamp changes without adding a target read. Parse +only the existing fixed inventory record forms; malformed records produce a +fixed diagnostic-refused status and never arbitrary strings/errors. No body, +relative/absolute path, filename, target text, credential, unknown key or raw +parser/OS error is serialized. Hashes must be fixed lowercase SHA256 values. + +Keep the complete serialized delta at most2KiB, with a fixed bounded fallback +if serialization or its bound refuses. All exact count/entry-limit/refusal +statuses remain diagnostic facts. Do not truncate native output, change the +native archive/member/byte limits, ignore logs, replace before with after, +filter either profile map or change the original full-map fatal/flags. + +## Meaningful controls and genuine follow-up + +Use real owned temporary Qoder profiles and the actual existing complete +inventory before/after explicit controlled mutations. Cover unchanged maps, +log file byte/mode changes, added/removed logs and empty directories, settings +and plugin-cache changes, exact latest rotation and same-target rotation. +Check exact count/area/operation/type/size/hash facts against the held records, +with bounded deterministic detail selection and an explicit omitted count for +more than three changes. Private/control/long path names, target text and file +body canaries must never appear in serialized output. Taking the diagnostic +must not further change the already mutated profile's metadata or bytes. + +Synthetic malformed records, oversized maps and the maximal admitted metadata +shape must exercise fixed refusal/bounds without raw-string leakage. Mutate the +returned diagnostic, where applicable, to prove no alias into either original +map. Retain every existing Qoder ordinary-profile mutation, bounded refusal, +log-link no-follow/closure/rotation, opaque catalog and fixed argv/scope contract. +No positive hosted guard or native process is run locally. + +Obtain two independent plan GOs before source edits, then independent complete +code reviews and actual focused Qoder/shared contracts plus both affected and +unfiltered size/architecture lint gates in a granted exclusive slot. Preserve +the current source-bound16-member failure envelope; the unchanged Python +admission can replay it. Root alone publishes to existing PR523 using a fresh +non-forced expected-head lease. No release/new PR/VS work. + +A new genuine capture must establish the actual write class and metadata. +Any later preservation-policy, expected-fixture or logging-authority amendment +needs its own concrete source/evidence-backed plan and reviews. The current +catalog demonstrates exact flag-view inventory, while its original-profile +write still blocks read-only catalog preservation and all later native startup/ +full-cycle claims. The earlier component-cycle design remains conditional; +this diagnostic neither promotes its catalog schema nor implements that cycle. + +## Validation record (2026-10-27) + +Root and shell independently approved the exact plan above before source edits. +Both reviewed the complete formatter, unchanged fatal boundary and actual-file +controls. Their findings corrected the formatter's file-record limit to the +existing inventory's 64MiB and added independently expected detail metadata, +link-record hashes and deterministic selection controls. Both approved the +corrected code; the sole later source delta uses Go1.22 integer range for the +4097-entry refusal test after the affected lint reported `intrange`. + +The final focused inert Qoder, log-link and shared argv/scope contract selection +passed in 0.049s with Go1.26.10, `-p=1`, `-count=1` and a 90-second timeout. +The all-enabled affected-line lint from plan commit `85c6e4c6` reported zero +issues. The unfiltered whole-file `revive,funlen,gocyclo,gocognit,dupl,depguard` +gate also reported zero issues. Gofmt and whitespace checks are clean. + +Final SHA256 values are `9af92f1e609ea12922851664058cd807950bab695e084311bef8cb9f462ca392` +for the existing shared attempt file and +`32a95141f2cd4cb51930ddea5d5430be8cfe70b4fe91284db326a511dafe4740` +for the new formatter/contracts file. The unchanged Python admission replay +accepted the audited source-bound `ccd9dc9e` 16-member failure with all five +qualifications, vendor authentication and real-model qualification false. +No vendor client or positive hosted admission ran locally. A fresh genuine +hosted capture remains necessary to identify the original-profile mutation. diff --git a/docs/plans/project-install-e2e/qoder-other-profile-delta-priority-plan.md b/docs/plans/project-install-e2e/qoder-other-profile-delta-priority-plan.md new file mode 100644 index 000000000..027dde7a1 --- /dev/null +++ b/docs/plans/project-install-e2e/qoder-other-profile-delta-priority-plan.md @@ -0,0 +1,113 @@ +# Qoder: prioritize the measured unknown profile changes in the same diagnostic + +## Exact published baseline and newly closed result + +Current PR523 head `94e0c6b9807ed5f37301eca9927b3f3227c0d0cb` has tree +`358e54f9e94487c33c73d56306747e0bce348124`, identical to reviewed local +`854e769840b4da9d459fe24738bb33e83961c3af`. Preserve the original plan, +link policy, exact complete profile maps, three-entry diagnostic cap and all +native/public/source/authentication/cleanup/refusal gates. + +Genuine run40467129367/native job122068137876 passed public add-a, then native +catalog exit0/error=false/deadline=false in2999ms. Its catalog remains one raw +row; ordinary startup did not run. The original complete-profile comparison +still fails, as required. The new diagnostic measures before_entries8 and +after_entries18, added10/changed1/removed0. Exact area counts are log-latest1, +logs3, other7; settings, plugin-cache, plugins and cache are zero. + +The prior fixed area ordering selected the changed latest link plus two new +log files (994 and9133 bytes) and omitted8 changes. Thus none of the seven +other-area entries was projected. The output does not establish those paths, +kinds or purposes and cannot justify a logs-only exception. Do not assume the +other changes are harmless defaults, cache, identity, authentication or state. + +The closed native artifact12717861327 has16 members: outer SHA256 +`ef60ec6cea0222b828716a908ba04708dae5bd6dde80543df6d47aab13d2479f`, +inner `5a25c6fba75f9d78a2e91756f81e90acb0912bc6190a98cdd492396b87e0fd40`. +The closed frontend12717068850 has25 members: outer +`50ba00d16869be9e501c74eb7eb6e2faeb09c09a262102daad81ed3aeaef5f67`, +inner `8e31bc5894ee52df8cae4d07d1c8ed71e86af73adcc48ef3e23a404659ec96c3`. +API size/hash, canonical unique ordinary ZIP membership/CRC, source94e/tree358, +empty source/build-clean streams, all24 frontend command-stream byte/hash joins, +exact native source identity/empty patch and unchanged sixteen-member failure +admission were independently verified. All five qualifications, vendor auth, +real model and runtime_attempt_complete remain false. The finite audit lives +under /tmp/uap-qoder-current-94e/source-and-stream-audit.json. + +## Narrow selection-only amendment after two independent plan GOs + +Change only the existing delta formatter's detail ordering and one new bounded +Linux contract file, plus this plan's factual validation record. Do not change +the shared fatal hook, profile/link readers or accepted record parser. Preserve +all counts, area names, SHA projections, record grammar, 4096-map/8192-union +bounds, three-entry limit, omitted count/status and complete2KiB fallback. + +When the already computed exact other-area count is nonzero, sort other-area +details before every known-area detail. Within other retain exact key-SHA256 +ordering. After that subset retain the existing fixed relative order and +key-SHA256 tie-break for latest/logs/settings/plugin-cache/plugins/cache. With +zero other changes the old ordering remains byte-identical. This changes only +which already parsed details fit in the same bounded diagnostic; no new field, +raw name, private path, body, target, error or filesystem read is introduced. + +All changes continue contributing to exact totals even when omitted. In the +observed eleven-change shape, only three of seven other details can fit and +omitted_count remains8. Report that incompleteness truthfully; do not describe +three samples as a complete account of seven entries. No baseline adoption, +ignored area, native schema approval or logging permission is authorized. + +## Meaningful controls and genuine follow-up + +Use real owned Qoder fixture profiles and the unchanged complete inventory. +Add seven private-name ordinary files plus known log changes; independently +state the selected first three key digests and their exact added/file/mode/ +size/content-digest metadata, total/area/omitted counts and deterministic order. +Also cover one other change with known changes to prove the remaining slots +retain their original order, no-other changes to preserve old selection, +reverse map insertion order and returned-output/input-map non-aliasing. + +Retain original malformed/bound/maximal-record/link-rotation/64MiB/private +serialization contracts. The actual profile's bytes and metadata must remain +unchanged by projection, and complete diagnostic serialization stays below +2KiB. Keep the existing400-line file within its size gate by replacing only +the old comparator return with a call to a small pure comparator in the new +helper/contracts file. Do not reshuffle existing tests or suppress a lint gate. + +After root and another independent plan GO, implement the finite ordering +change, obtain independent complete code reviews and run focused existing/new +Qoder/shared inert contracts, all-enabled affected-line lint and unfiltered +whole-file size/architecture lint in an explicitly granted exclusive slot. +No local vendor/client or positive hosted guard. Root alone publishes reviewed +incremental commits to the existing PR523 using a fresh non-forced head lease. + +A new genuine source-bound capture must identify the selected other-area +metadata. Further diagnosis/source research may still be needed for omitted +entries or to attribute hashed names; no preservation-policy change follows +from this selection amendment. The original fatal profile comparison and all +qualification/authentication/model flags remain unchanged. No release, new PR +or VS Code work. + +## Validation record (2026-10-27) + +Root and CLI independently approved the exact plan before implementation. +CLI and shell independently reviewed the complete two-file change and gave +code GO for SHA256 +`beffe0727d8a9285c5b4df22150d6ea83c6c6400a024285a0bf15eab8ed5700c` +(existing formatter) and +`149291846c252ff44c633b02e28ef473f9c02a992118e33d9700e85872c425fb` +(new pure comparator/contracts). No source changes followed those reviews. +The old formatter remains400 lines; the new helper/contracts file is107 lines. + +Actual focused existing/new Qoder, log-link and shared argv/scope contracts +passed in0.053s with Go1.26.10, `-p=1`, `-count=1` and a90-second timeout. +The all-enabled affected-line lint from plan commit `104cc6c9` and unfiltered +whole-file `revive,funlen,gocyclo,gocognit,dupl,depguard` gate each reported zero +issues. Gofmt and whitespace checks are clean. The actual-file seven-other +case reproduces10 additions/one change/three details/eight omissions; this is +an inert shape control, not identification of the seven genuine unknown paths. + +The recovered source-bound94e sixteen-member failure and all24 frontend +stream joins were reverified with unchanged failed/unqualified Python admission. +No vendor or positive hosted guard ran locally. A new genuine capture must +still identify the newly prioritized metadata before any preservation-policy +or native/lifecycle qualification amendment. diff --git a/docs/plans/project-install-e2e/qoder-preserved-log-link-plan.md b/docs/plans/project-install-e2e/qoder-preserved-log-link-plan.md new file mode 100644 index 000000000..7ff8c487d --- /dev/null +++ b/docs/plans/project-install-e2e/qoder-preserved-log-link-plan.md @@ -0,0 +1,138 @@ +# Qoder exact original log link: preserve metadata without following aliases + +## Observed current refusal + +Published PR523 head `c14b4974ddd42d16233ad654f3dbc50bcbcabcf0`, tree +`9197585febf142cc586712c04590cd06a967c17a`, has genuine runtime run +`40455028917`, native job `122026305662`. Public add-a succeeds (exit0, +error=false/deadline=false, 569 ms), then the first original-profile inventory +refuses before native catalog/startup with: + +`Qoder profile ordinary single-link file required: entry="logs/latest" mode=Lrwxrwxrwx nlink=1 size=42` + +The owner check preceding that refusal passed. This proves an original-user-owned +symlink at this exact relative entry. It does not capture the target bytes, +target kind/ownership or containment, nor establish which earlier command +created it. No source or runtime assumption may fill those gaps. + +Native artifact `12711428594` outer SHA256 +`eee6372ce39902fe9269f652632792bb5ab24cb16e8f1cf63e30ac50ac9681a6` +and frontend `12711149158` outer SHA256 +`9ac977e326a940f96a3e1fa96e4e67edd91438aa9aa47750e7aca0c43cd033bb` +were checked as 13/25 bounded canonical unique ordinary flat ZIP members with +valid CRCs, exact source/tree, empty source-clean streams and matching frontend +command stream hashes. All qualifications remain false. + +Local `51accde02931ff08158f47b94c2a195b5881fdbe` has exactly the current +published tree. Its accepted bounded metadata diagnostic remains preserved. +The preceding worker branch is retained; this slice has its own branch/plan. + +## Decision and retained guarantee + +A symlink can be inventoried without granting it filesystem authority if its +own held identity and exact link bytes are preserved, it is never followed, +and its lexical target and every target ancestor are confined to ordinary owned +entries already covered by the same complete profile inventory. Implement this +only for the observed exact `logs/latest` entry. All other symlinks and every +hardlink remain refused. Do not exclude logs, caches, new directories, changed +modes, bytes or link targets from the complete pre/post catalog comparison. + +This does not assume the catalog is read-only in practice. If it rotates the +link, writes a log or otherwise changes the frozen profile, the existing fatal +comparison must still fail; no normal-logging exception is authorized here. + +## Finite implementation after two independent plan GOs + +Add one private Linux helper for that exact entry. Keep the current root/parent, +owner, entry/depth and ordinary-file checks and their order; call the helper +only after the existing Lstat/owner check and only when rel is exactly +`logs/latest` and the leaf is a symlink. Require its observed symlink mode, +original UID/GID, nlink1 and a positive size at most4096. Include link bytes in +the existing256MiB inventory budget; no new unbounded read is introduced. + +Hold the ordinary original profile and logs directories with O_DIRECTORY, +O_NOFOLLOW/O_CLOEXEC descriptors and compare held/linked inode identity. Read +only `latest` with bounded Readlinkat on that held logs descriptor; do not use +EvalSymlinks, open or read through the symlink. Compare the leaf's held +AT_SYMLINK_NOFOLLOW stat before/after the read with the already observed Lstat, +and recheck both linked ancestor identities. Require exact target byte length +and stable inode/device/mode/owner/link-count/size/timestamps. Close every held +descriptor with checked errors. A race, alias or close failure refuses. + +Interpret those bounded bytes only as a canonical nonempty relative path: +valid UTF8, no NUL/control, absolute/volume spelling, backslash or parent escape; +clean path equality and bounded component depth are mandatory. Resolve only +lexically beneath original `.qoder/logs`, then inspect each target component +relative to held descriptors without following symlinks. All target ancestors +must be ordinary original-user-owned directories; final target must be an +ordinary owned directory or single-link regular file. Self-links, dangling +links, absolute/outside targets, target/ancestor aliases, nonregular types and +multiply linked files refuse. Do not open or read target contents in this helper. + +The ordinary target and complete descendant closure must also appear in the +unchanged normal profile walk; validate that requirement before admitting the +inventory. Store only an unambiguous symlink record containing its mode/link +metadata, target byte count and SHA256 of exact target bytes. The target text +stays private. Exact before/after map equality freezes the link along with every +other entry; do not adopt a native-written baseline or retarget/delete the link. + +Record only finite no-follow/contained-target type, target byte count and target +SHA256 as a small original-log-link observation in existing runtime-attempt.json +after complete initial inventory succeeds. Unknown/unsafe target shapes keep +the original failure, adding only a fixed refusal category and bounded held +metadata; never serialize raw link text, absolute paths, log contents or errors. +If the actual42-byte target fails any rule, retain the capture and require a +separate source/evidence-backed plan; do not add a fallback or broaden acceptance. + +## Scope, meaningful checks and publication + +Scope is the existing shared CLI attempt file, one new Linux Qoder log-link +helper/contract file and this plan/validation record. Preserve all earlier +diagnostics, other-client paths, opaque catalog grammar, exact argv/cwd and +budgets, source/pins, original HOME/profile authority, installer/receipt/security, +native trust/authentication/permission, supervision/cleanup and all qualification +flags. No production adapter, user profile relocation, auth workaround, blanket +symlink allowance, ignored subtree, new process, new PR, release or VS Code work. + +Actual inert temp-file contracts must cover the sole contained ordinary link +and its unchanged complete target closure, plus other-entry links, hardlinks, +absolute/outside/unclean/self/dangling targets, aliased ancestor/target, FIFO, +oversized target text and changed link/target/empty directory/mode/content. +Verify refusal is before unsafe content reads, metadata records contain no +target text or private sentinel, link/target identity/bytes survive unchanged, +and changed target bytes or any new log entry cannot compare equal. Keep all +existing Qoder full-profile mutation and finite command/opaque JSON contracts. +Use only the root-granted exclusive Go/lint slot for focused contracts and both +affected lint gates; inspect exact scope, obtain independent code review, and +let root publish to existing PR523 using a fresh non-forced ref lease. Only a +fresh genuine source-bound run can establish whether catalog/startup proceeds. + +## Actual implementation validation + +The original plan SHA256 `6e45e544bc368a0974ca94196472771642210d735e442c2a07744cace84cecae` +received independent CLI and shell plan GOs plus root review before code. Both +critics reviewed the complete two-file implementation and its final small +preallocation/positive-contract delta. The unchanged shared attempt file has +SHA256 `d2571a53a42f70486967c96298b6fd5c1ca34036d511814169eb18a36c796020`; +the final new helper/contracts have +SHA256 `cbfe3f4ffa325c742a0123939813354197eaf0dcf8a52d5a3bdbbb59c98ebeba`. + +Actual focused inert Go tests passed in `0.028s`: five new log-link suites with +23 directory/file, unsafe-target, alias/hardlink/FIFO and mutation subcases, +together with the retained Qoder catalog/profile/diagnostic and exact argv/scope +contracts. Actual all-enabled changed-line lint and unfiltered whole-file +size/complexity/architecture lint each reported `0 issues`; gofmt and whitespace +checks pass. The first linker attempt exhausted SHM, and the first lint pass +found one preallocation issue plus exhausted SHM fact-cache writes. After root +freed an independently verified duplicate toolchain, the byte-identical canonical +Go1.26.10 and task-owned disk temp/lint cache completed the checks. Direct source +indexing (`GODEBUG=goindex=0`) avoided the stale index after the compiler path +change. No vendor process ran locally and no native qualification was inferred. + +The symlink record includes the stable numeric link and target metadata as well +as exact target byte count/SHA256, so replacing a link with the same target text +cannot compare equal. Actual same-target rotation and unchanged original-link +identity contracts cover that boundary. Target text and contents remain private; +the ordinary target closure and existing complete pre/post map comparison remain +mandatory. Actual native target shape and any catalog log mutation remain for a +fresh genuine run; an unsafe target or changed log still fails. diff --git a/docs/plans/project-install-e2e/qoder-profile-refusal-diagnostic-plan.md b/docs/plans/project-install-e2e/qoder-profile-refusal-diagnostic-plan.md new file mode 100644 index 000000000..dfa67fe25 --- /dev/null +++ b/docs/plans/project-install-e2e/qoder-profile-refusal-diagnostic-plan.md @@ -0,0 +1,92 @@ +# Qoder original-profile refusal: bounded metadata diagnostic + +## Observed boundary and exact current source + +Published PR523 head `0d1bfa7225937f4f581958022ef103200ee14301`, tree +`74242f382c0c738b4a13a95547b2d8102b461566`, has genuine runtime run +`40408766184`. Native artifact `12699200113` and matching frontend +`12698695352` retain successful public project installation followed by +`Qoder profile ordinary single-link file required`. The failure happens during +the first complete original `HOME/.qoder` inventory, before the selected native +catalog or startup command. The closed capture does not identify the offending +entry, file type, link count or size; no particular cause is established. +All five native qualification flags remain false. + +Local baseline `4106c6f9a942f3fadd26b29e109f4ceb4dbe68a5` has exactly that +published tree. It preserves the original worker branch and mirrors only the +published runtime-workflow overlay, immutable blob +`66fb12161a3d1cfe6992cfeada8fbf44ad54fda6`. No other baseline bytes changed. + +## Narrow diagnostic change + +After two independent plan GOs, change only the existing ordinary/single-link +refusal in `projectNativeCLIQoderProfile` to retain its exact reason prefix and +append four metadata fields from the already obtained `os.Lstat` result: +the relative entry, `info.Mode()` as a finite mode string, `identity.Nlink`, +and `info.Size()`. Keep the current refusal predicate and its position before +the existing byte accounting or bounded body reader unchanged. + +Use a small private formatter for that error. The relative entry is limited to +256 input bytes with an explicit truncation marker, and `%q` quotes/escapes it +so names containing controls cannot produce extra log lines. The complete +diagnostic is finite (at most 2 KiB), contains no absolute HOME/profile root, +and includes no file contents, link target, credentials or directory dump. +Do not follow the entry, call Readlink, reopen it or add filesystem reads. +Keep all original ancestor/owner, directory, count/depth, byte, ordinary-file, +single-link and stable bounded-read checks and their order. Do not admit, +remove, move, relabel or repair the refused entry. The error still terminates +the native fixture before catalog/startup; artifact closure and qualification +flags remain unchanged. + +## Meaningful inert contracts + +Exercise the actual profile inventory with real temporary ordinary parent +directories and separate refused symlink and hardlink entries. Compare the +diagnostic metadata against the actual entry's `os.Lstat` mode, size and link +count; ensure the relative entry is reported and the absolute root, foreign +target path and sentinel target contents are absent. Verify both entries and +their outside target remain unchanged after refusal. An actual nested symlink +whose relative name exceeds 256 bytes and contains quoted/control characters +checks truncation, the finite diagnostic bound and absence of raw line breaks. +No native binary, installer, model, network or subprocess runs. + +Preserve the existing full-profile mutation contracts (bytes, modes, new empty +directory, new cache, alias and hardlink), opaque strict whole-JSON catalog +contract and finite command/argument/client/cwd/deadline controls. Add no skip, +fake filesystem metadata, synthetic native response or acceptance relaxation. + +## Scope, checks and publication + +Scope is exactly the two existing Linux Go test files +`repotests/agentplugins_project_native_cli_attempt_test.go` and +`repotests/agentplugins_project_native_cli_contract_test.go`, plus this plan and +validation record. No production/client adapter, installer, source/pins, user or +project authority, profile baseline, permissions/trust/authentication, original +deadline, process supervision, cleanup or qualification policy changes. +Useful legacy source remains preserved. VS Code is excluded by the owner's +latest instruction and is not part of this work. + +After the shared exclusive Go/lint slot is granted, run the affected existing +and new inert Qoder inventory/catalog/command contracts, then actual affected +all-enabled changed-line lint and the whole-file size/architecture gate. Run +gofmt/whitespace checks and obtain independent code review before root-owned +publication to existing PR523; no new PR or release. Fresh genuine hosted raw +evidence must identify the refused entry before a separate behavioral plan can +be considered. Passing inert diagnostics does not qualify native operation. + +## Review and actual validation + +Plan SHA256 `65bb9cf95226fae7efb64928db07abb5827bc5720025c5e59f8130874deccb6c` +received independent CLI R1 and shell R2 GOs before plan commit +`255247bdc1870178cc272484c2350b3c1bd82779` and implementation. Both critics +reviewed the final code bytes, including the mechanically removed redundant +link-count conversion reported by actual unconvert lint. Final focused inert +Qoder inventory/catalog and exact command contracts PASS in 0.010 seconds, +including all three new actual link/metadata cases and all six retained profile +mutation cases. Actual all-enabled changed-line lint and the unfiltered +whole-file size/architecture gate each report 0 issues; gofmt and whitespace +checks are clean. An initial invocation stopped before tests because disabling +the repository's required Go workspace hid its local nested modules; the +unchanged existing go.work was then used for the successful checks. No vendor +or network process ran, no qualification changed, and fresh genuine hosted +diagnostic evidence remains required before any behavioral correction. diff --git a/docs/plans/project-install-e2e/remaining-native-qualification.md b/docs/plans/project-install-e2e/remaining-native-qualification.md new file mode 100644 index 000000000..21a579c87 --- /dev/null +++ b/docs/plans/project-install-e2e/remaining-native-qualification.md @@ -0,0 +1,5097 @@ +# Remaining native project qualification + +## Owner reprioritization, 2026-10-27 + +The owner explicitly deferred VS Code: it is not a priority and is skipped in +this continuation. Complete the nine remaining client leaves in PR521-529 and +their applicable end-to-end verification, independent review and merge gates. +Keep PR530 as a deferred draft; preserve its existing source, recorded evidence +and unpublished work. Do not run new VS Code qualification, change its dedicated +implementation or merge that leaf as part of this continuation. Its incomplete +qualification does not block the active nine-client program. Preserve existing +baseline regression coverage for previously supported behavior. + +This latest scope decision supersedes earlier instructions below that require +VS Code follow-through or count it among the active remaining targets. It does +not change the evidence requirements for any active client, promote a blocked +native case to passed, or authorize a release. + +2026-10-25. Work in progress; source-only, not release qualification. +Baseline: `d5c16856cef67a1457704971d46765739141ab08` (project implementation +#499 and evidence cleanup #519). The owner requests completion of the remaining +agents' `--scope project` E2E with incremental commits/pushes. This plan does not +claim that an unexecuted scenario passed. + +## Authority and review + +Follow [owner scope](../../PROJECT_INSTALL_OWNER_SCOPE.md), including the narrow +VS Code project exception, original-user authority and existing transaction, +ownership and package-store architecture. Preserve legacy implementations and +tests. Keep published release availability separate from source qualification. + +Workers and independent reviewers use the owner's GPT-6.1 Sol/xhigh selection. +Before implementation, review each slice in two independent rounds and resolve +findings. A client owner does not approve their own slice. Record review results +in the PR, with the exact reviewed commit/tree. Each client has a separate PR +stacked on this program branch. Product changes discovered by a spike receive a +specific amended plan and the same review gate before implementation. + +Keep this as one consolidated plan. Do not add per-command logs, expanded +captures or separate repetitive review documents to Git. Raw evidence belongs +in bounded CI artifacts; retain concise source-bound conclusions and links. + +## Required evidence + +There are ten remaining client targets: `gemini`, `copilot`, `kiro`, `cursor`, +`cline`, `qoder`, `windsurf` (existing `devin` alias), `kimi`, `grok`, and `vscode`. +Claude/Codex/OpenCode existing native gates remain intact. OpenCode project MCP +is a separate optional follow-through after the requested remaining targets. + +Every client receives public UAP project lifecycle coverage and genuine native +observation for its supported surface. Distinguish installed ownership, native +discovery, MCP initialize, tools/list, tools/call, authentication and model use. +Prepared is not globally promoted to Active because a trusted fixture passed. + +Required lifecycle: empty baseline; install distinct A/B packages and an +independent original-user marker; unchanged reconciliation; move source/update +A; remove one exact owned component/repair from the recorded pin; fresh native +process or workbench restart; remove A and repeat removal. Require exact selected +source, revision/path/identity and correct absence after removal. Verify B, +foreign native content, original-user authority and retained plugin data. + +Use the existing harmless native MCP probe and fresh nonce. A runtime-positive +claim requires native-driven initialize/tools/list/tool-call events, matched +native/probe session and returned result, selected package/data roots and cwd. +A connected label, package list or direct test call to the probe is insufficient. +ACP receives no inline MCP definitions; config injection cannot prove discovery. +Qoder's documented explicit session plugin selection and Cline's process-wide +MCP override are separately named activation modes, not cwd autodiscovery. + +## Execution boundary and shared infrastructure + +Native/vendor execution occurs only on genuinely disposable, supported +GitHub-hosted machines. Check actual platform, `GITHUB_ACTIONS`, +`RUNNER_ENVIRONMENT` and explicit native opt-in before the first child, including +Linux. Never synthesize host eligibility locally. Inert parser/protocol tests may +run locally; they do not qualify a vendor process. + +The new VS Code trusted runtime starts on the already reviewed `ubuntu-22.04` +workspace host, preserving its ordinary-user, NNP, strict cgroup admission, +Xvfb and standard Electron sandbox contract. Record the actual image/version. +The earlier Ubuntu 24.04 failure is not an invitation to use `--no-sandbox`, a +setuid-helper workaround, privileged launch or another process primitive. +Unsupported admission fails; an image change needs its own reviewed amendment. +See [the retained host plan](vscode-workspace-host-plan.md). + +Use a fresh original user profile plus separate real Git projects A/B and an +outside cwd. A project never becomes HOME. Explicitly allowlist child environment; +do not inherit credentials, proxies, account state, shell configuration or the +workflow GitHub token. Do not claim a network firewall that is not implemented. +Every new Cline child, including version/help, receives literal +`CLINE_NO_AUTO_UPDATE=1` through the preserved runtime-environment contract. +Refuse a pin where that documented control no longer applies. Use documented +updater suppression for other clients where available and verify immutable +runtime-file identities before/after observation; changed bytes cannot continue +under the old pin. Freeze Cline tool approval explicitly rather than inheriting +its CLI's auto-approval default; reject unexpected built-in tool requests. + +Exact owned A/B trust can be authored through documented native configuration or +native UI/API before preservation baselines, following the existing +[trusted-fixture amendment](priority-trusted-native-plan.md). Record that setup +separately from observed trust. UAP itself never changes trust. No forged trust +database, blanket trust-disabling flag, authentication bypass or fabricated +vendor account is permitted. + +An officially supported custom provider may point to the existing scripted +loopback fixture. Label it as a test provider; its own optional test credential +is not vendor OAuth evidence. Never inherit or publish real credentials. Native +local bearer tokens stay private and are redacted from artifact transcripts. +In particular, Kimi startup raw streams, generated token files and auth/provider +configuration stay in a private capture directory outside artifact admission. +Parse the native token privately, redact diagnostic streams before copying them +into the admitted evidence namespace, and upload only the closed evidence set. +An inert admission test must reject a known token canary in JSON, transcripts +or archive members. Do not retain bearer-bearing URLs as public source evidence. + +Reuse `native_client_research.run_probe`, existing native fixture/capture and +process containment, source/provenance checks, the native MCP probe and existing +loopback-provider patterns. No second installer, generic RPC framework or +speculative client registry. Extend pinned acquisition only for concrete formats: +Node/support-file distributions and full Kiro companions, with bounded extraction +and regular-file/path checks. Do not execute package install scripts. + +Root owns shared acquisition, source identity, process/evidence helpers, workflow +registration and support wording. Client owners own leaf collectors/parsers and +native lifecycle cases. Use source-only project jobs without weakening released +client evidence. Register clients and exact required tests explicitly as their +slices arrive; the final program cannot complete with a missing target or case. + +Typical budgets: help/list 30 seconds, one session/tool observation 60 seconds, +one MiB per captured stream, six minutes per initial research client. Long-lived +native services have explicit total deadlines, owned child cleanup and shutdown +evidence. Fail on overflow, timeout, malformed results, unsafe artifacts or +missing required observations. Reuse existing closed artifact admission rather +than recursively uploading a native profile. + +Research completion and qualification are distinct. Research can record an +explicitly planned native authentication/unsupported boundary, with raw bounded +evidence and all affected qualification flags false. A required runtime case +fails if blocked, skipped, not reached or missing evidence. Never convert an +arbitrary nonzero exit into an expected boundary or a successful qualification. + +### Concrete phase and leaf contract + +This two-round plan gate initially authorizes shared acquisition and bounded +research collectors, not an unobserved product change or guessed session +protocol. `acquire` requires `.acquisition`; `observe` additionally +requires `.help` and `.scope-observation`. A research runtime +attempt is separately registered as `.runtime-attempt`. Cursor/Grok +cannot enter `observe` until the reviewed immutable acquisition amendment. +Unknown flags/schema, malformed output and unrelated failures are failures, +not supported-boundary records. Only a measured explicit authentication or +unsupported-native-capability response can complete a planned boundary attempt. + +The initial Kimi/Cline help-only leaves explicitly declare `help`, which selects +only acquisition and help. It cannot satisfy scope observation. Leaf +`AVAILABLE_PHASES` (or the unconditional acquisition-only declaration) registers +the exact initial phase in the shared research matrix; missing leaves stay +visible as outstanding program work. The initial shared runner never emits a +positive qualification flag, and accepts only explicit passed selected research +IDs. Structured observations may be a JSON mapping or list; they cannot set case +success by themselves. Raw private files are never enumerated for upload. + +Gemini's reviewed `gemini.js` bundle uses the exact Node **24.21.0** Linux x64 +runtime, acquired from +`https://nodejs.org/dist/v24.21.0/node-v24.21.0-linux-x64.tar.xz`, SHA256 +`fd8e59d5a511510f6a298afb548f18c7d2b1be404d8b4a27d94fbe49f56cb2d6`. +Only the exact regular `node-v24.21.0-linux-x64/bin/node` member is materialized; +the archive is verified before extraction, version is checked before the client, +and runtime/support-file bytes are verified before and after every probe. No npm +installation or package lifecycle script is used. This does not authorize a +TypeScript observer or SDK toolchain, which retains its separate amendment gate. + +All ten targets must be accounted for in the final matrix. A successful research +job does not satisfy any qualification ID. The required follow-through IDs for +an installation/discovery claim are `.project-lifecycle` and +`.native-restart-removal`; a native MCP claim additionally requires +`.mcp-initialize`, `.mcp-tools-list` and +`.mcp-tools-call`. An outstanding boundary remains visible and unqualified, +never a substituted pass. After observation, freeze exact native mode/argv, +schemas, tool approval, source entrypoint and selected Go test names in a concise +amendment here; independently review it twice before coding that runtime slice. + +Collectors are closed, client-specific leaves under +`scripts/project_native_collectors/`; their inert contracts belong in +`scripts/test_project_native_.py`. Root owns shared entrypoint, +acquisition/host/process/artifact helpers and workflow registration. This fixes +the initial file ownership without creating a new plugin or RPC framework. + +| Client ID | Owned collector | Subsequent native fixture prefix or controller | Mode to freeze after observation | +| --- | --- | --- | --- | +| `gemini` | `gemini.py` | `repotests/agentplugins_gemini_project_native_` | Installed settings, native session, supported Gemini loopback protocol and returned MCP tool result. | +| `copilot` | `copilot.py` | `repotests/agentplugins_copilot_project_native_` | Offline BYOK ACP/session with empty injected MCP list and exact named-tool permission response. | +| `kiro` | `kiro.py` | `repotests/agentplugins_kiro_project_native_` | Measured V2/V3/native ACP mode; config visibility and actual auth/startup response stay distinct. | +| `cursor` | `cursor.py` | `cli/cmd/agentplugins/project_cursor_native_` | Genuine list/list-tools source resolution, then separately admitted tool-execution mode. | +| `cline` | `cline.py` | `cli/cmd/agentplugins/project_cline_runtime_` | Real task using exact process MCP override, suppressed updater and explicit tool approval. | +| `qoder` | `qoder.py` | `cli/cmd/agentplugins/project_qoder_native_` | Explicit session plugin-dir, pinned runtime/SDK, exact initialized plugin/skill source and absent-path control. | +| `windsurf` | `windsurf.py` | `repotests/agentplugins_devin_project_native_` | Genuine Devin skills/MCP discovery; any auth-required tool tier stays separate. | +| `kimi` | `kimi.py` | `repotests/agentplugins_kimi_project_native_` | Native authenticated local API resolves installed entry by name/cwd; native prompt tool result is a separate case. | +| `grok` | `grok.py` | `repotests/agentplugins_grok_project_native_` | Observed plugin versus direct project path; actual source/trust/connection before any adapter change. | +| `vscode` | `vscode.py` | `install/integrationctl/research/vscodeprojectruntime/` and `scripts/vscode-project-runtime-observer/` | Trusted native development host; correlate gateway endpoint with exact definition metadata and nonce/package/data/cwd, not label alone. | + +The Go prefixes above admit focused `_test.go` leaves only, preserving existing +fixtures. The initial shared/collector PRs cannot assert these later cases are +implemented merely because their research completed. + +## Frozen candidates and initial observations + +Pin every executable before execution. Cursor and current Grok start with an +acquisition-only stage: download immutable official bytes, bound size and record +digest/member inventory without executing them; review/freeze that pin before +the native observation stage. Existing pins are reused only for their own exact +version/platform. Measure main and companion binaries and any Node runtime. + +| Client | Candidate | Initial genuine observation and follow-through | +| --- | --- | --- | +| Gemini | 0.65.0, existing official bundle pin | `skills list --all`, `mcp list`; explicit trusted/untrusted A/B; native connection events; documented loopback Gemini provider for a harmless tool call. | +| Copilot CLI | 1.0.103, existing Linux archive/executable pins | `help providers`, `skill list --json`, `mcp list/get --json`; documented exact `trustedFolders`; offline BYOK ACP/native session with empty MCP injection and narrow tool approval. | +| Kiro | 2.34.0, current official manifest | Actual help, `mcp list workspace/global`, `mcp status --name`; freeze observed engine and 2.34 trust semantics; bounded actual ACP session attempt. Config listing cannot stand in for startup if genuine auth is required. | +| Cursor | 2026.10.22-27dcf5f, digest pending acquisition | Exact launcher/Node distribution; actual help, `mcp list`, `mcp list-tools`; correlate native handshake; investigate supported authenticated/custom-provider tool path separately. Preserve legacy auth-skipping tests without borrowing their semantics. | +| Cline | 3.0.73, existing pin | Preserve metadata/source-selection gate. New real runtime fixture uses exact cwd plus `CLINE_MCP_SETTINGS_PATH`, actual installed MCP connection/tool evidence and ordinary-user-source negative control. Supported provider/auth behavior must be observed first. | +| Qoder | 1.1.78, existing pin | Verify `--plugin-dir` and actual session plugin/skill inventory using UAP's existing closed view; exact A/B revision and fresh-session absence. Pin any official SDK and force the selected vendor executable. MCP requires a separately reviewed closed-view extension after observation. | +| Devin Local | 3000.11.205, existing pin; target `windsurf` | Actual skills list/paths/show and MCP list/get across lifecycle; require native startup/tool events separately. Observe bounded auth boundary if no supported account-free tool surface exists. | +| Kimi Code | 2.3.2, official asset digest; retain observed 2.3.1 contract | Genuine `kimi web --no-open` local API: native bearer, own A/B workspaces/trust, skill catalog and MCP origin/test by name+cwd. Supported loopback provider can drive actual tool use. Qualify new bytes before narrowly admitting 2.3.2. | +| Grok Build | 1.0.70, digest pending acquisition | Actual inspect/skills/plugin/MCP help and doctor. Observe trusted bundled plugin MCP versus documented project `.grok/config.toml`. Implement only the observed path; no speculative fallback. Documented BYOK loopback may drive the tool call. | +| VS Code | 1.143.1, existing publisher pin | Preserve untrusted metadata observer. Separate real trusted development-host UI and `lm.startMcpGateway()` collector; initialize/list/call through the vendor gateway, exact installed server identity, restart/removal and cleanup. Label proposed-API/development-host scope. | + +New observer source uses TypeScript (`.ts`); generated JavaScript is a build +artifact, not a new tracked `.mjs`/`.cjs` implementation. Preserve existing +observers and reuse repository tooling rather than introducing another stack. +Before implementing/executing an observer or SDK-backed path, a reviewed leaf +amendment freezes exact Node, compiler/bundler and SDK versions plus integrity +or a committed lock containing immutable resolved artifacts, the build command +and output location. Existing CJS observers do not supply a TypeScript build +contract by implication. No `npx`/latest resolution or package lifecycle scripts; +emitted JavaScript stays under the job's temporary artifact/build directory, +outside the checked-out source. One concrete shared TypeScript toolchain suffices. + +### New immutable pin material already available + +- Gemini bundle SHA256 + `bb5e7e879608bd9b3fe261930d3886fa56aacbf471da1655f2978eb35b705a73`, + 21,215,960 bytes, official `google-gemini/gemini-cli` release `v0.65.0`. +- Copilot archive SHA256 + `9aeb4430e9ac9523546db07b227c7aba179a4710a55f9ac29ad143b0f9e1b325`, + 129,018,878 bytes, official `github/copilot-cli` release `v1.0.103`. + Executable SHA256 + `f19b3554a6b62605db3a26d5255ebe2a3ee39fcd6a357edb18301ea5037f6f0d`. +- Kiro [immutable 2.34.0 archive](https://prod.download.cli.kiro.dev/stable/2.34.0/kirocli-x86_64-linux.tar.xz) + SHA256 `11dce9286cf7401079cf4eac02a3d5982daac16a346d880109ec7b4a0b941040`, + 132,018,592 bytes. Do not reuse 2.33.1 companion hashes. +- Kimi [2.3.2 release](https://github.com/MoonshotAI/kimi-code/releases/tag/%40moonshot-ai/kimi-code%402.3.2) + Linux x64 archive SHA256 + `4715ccd1a591b64683929a14b26b3d07ac4c484e4da3881b22a2ccca56304042`, + 65,938,009 bytes; release source `b8dd3a134060c6e80ba4a1659335cd63b68483f2`. +- Cursor [immutable acquisition candidate](https://downloads.cursor.com/lab/2026.10.22-27dcf5f/linux/x64/agent-cli-package.tar.gz): + no native execution until its measured archive and runtime pins are frozen. +- VS Code proposed gateway declaration is present at the already pinned publisher + commit `e646868227c3e3a9e3f24277c8c7220be42c0be7`, declaration blob + `81e75fe69d74e82bdfb4ca69d0e89b801e728118`. + +## Primary references for the reviewed observations + +- Gemini: [skills](https://geminicli.com/docs/cli/skills/), + [MCP](https://geminicli.com/docs/tools/mcp-server/), + [configuration](https://geminicli.com/docs/reference/configuration/). +- Copilot: [BYOK](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/use-byok-models), + [ACP](https://docs.github.com/en/copilot/reference/copilot-cli-reference/acp-server). +- Kiro: [commands](https://kiro.dev/docs/reference/cli-commands/), + [permissions](https://kiro.dev/docs/permissions/), [ACP](https://kiro.dev/docs/cli/acp/). +- Cursor: [CLI MCP](https://cursor.com/docs/cli/mcp), + [permissions](https://cursor.com/docs/cli/reference/permissions). +- Cline: [CLI](https://docs.cline.bot/cli/cli-reference), + [MCP](https://docs.cline.bot/mcp/mcp-overview). +- Qoder: [session plugins](https://docs.qoder.com/cli/sdk/plugins), + [SDK MCP](https://docs.qoder.com/cli/sdk/mcp), + [CLI](https://docs.qoder.com/cli/cli-reference). +- Devin: [commands](https://docs.devin.ai/cli/reference/commands), + [MCP](https://docs.devin.ai/cli/extensibility/mcp/configuration). +- Kimi: exact 2.3.2 [server API](https://github.com/MoonshotAI/kimi-code/blob/b8dd3a134060c6e80ba4a1659335cd63b68483f2/docs/en/reference/server-api.md) + and [providers](https://github.com/MoonshotAI/kimi-code/blob/684bae9ea6a437f3bae98bba1dcb797a917d500b/docs/en/configuration/providers.md). +- Grok: [skills/plugins](https://docs.x.ai/build/features/skills-plugins-marketplaces), + [MCP](https://docs.x.ai/build/features/mcp-servers), + [BYOK](https://docs.x.ai/build/settings/reference). +- VS Code: [pinned gateway API](https://github.com/microsoft/vscode/blob/e646868227c3e3a9e3f24277c8c7220be42c0be7/src/vscode-dts/vscode.proposed.mcpServerDefinitions.d.ts), + [MCP operations](https://code.visualstudio.com/docs/agents/run/manage-mcp-servers). + +## Grok and Qoder measured acquisition to fixed help + +Genuine Grok run 40235269281, artifact 12615677952 (ZIP SHA256 +`b8cccd65c059fab3d157edd4bb26474b7eab547458f4d8cf46222072660c7331`), +measured the existing official 1.0.70 gzip at 76,760,282 bytes/SHA256 +`11d27a30adfb75c4b9b180072ab27412a1916f054ff5497ab70fb9a77d304bcc`. +Its sole `grok` executable is 195,700,192 bytes/SHA256 +`22d281c5964c5444147328096ba2a221f3f0874c6858e27c825656a80f6e58e9`. +Freeze those pins; admit only acquire/help and the exact nine commands: +`--version`, `--help`, `inspect --help`, `mcp --help`, `mcp list --help`, +`mcp doctor --help`, `plugin --help`, `plugin list --help`, `doctor --help`. +Each has 30 seconds, exit zero, no capture error, empty stderr and strict UTF-8. +Require exact requested Usage command followed only by a standard Clap +metavariable or end-of-line, plus --help; main identifies inspect/mcp/plugin. +The source-defined version candidate is one whole `grok 1.0.70 (<7..40 lowercase +hex>)` line with optional ` [stable]`; retain the actual compiled commit/channel. +Public source snapshot `xai-org/grok-build@2bdd1d6a6369de0e8c68132ea4539e9abd9e14a8` +is command guidance, not shipping-source provenance. Only `grok.help` may pass; +no inspect, trust, doctor operation, provider or MCP runtime executes here. + +Genuine Qoder run 40235270603, artifact 12615882073 (ZIP SHA256 +`09a2868892ec9c4eccd4a9f62d64a45c6024c977f51fa0bc524beb56ce5ae829`), +confirms the existing pinned archive and sole regular member `qodercli`, +182,982,112 bytes, matching the already frozen executable SHA256. Select that +entrypoint. Existing retained genuine 1.1.78 evidence (run 40079977099) already +binds exact version stdout `1.1.78\n` and `plugins` help; its parent Usage is +`qodercli plugins|plugin [options] [command]`. The next help-only table is +`--version`, `--help`, `plugins --help`, `plugins list --help`, `mcp --help`. +Require exact version and requested command-specific Usage, --help, zero exit, +no capture error and empty stderr, within 30 seconds each. Unknown main/MCP +grammar fails with bounded evidence; do not guess a successful shape. +Only `qoder.help` may pass. No import/list operation, session plugin, SDK, +user-cache registration, scope discovery or MCP runtime is part of this slice. +These pins and fixed-help additions retain every later qualification flag false. + +## Kimi initial API research amendment + +This next slice qualifies only observed research IDs, not a product version gate +or public-install lifecycle. Keep `kimi.help`; register `kimi.scope-observation` +only with the following actual native observations. Kimi 2.3.2/source +`b8dd3a134060c6e80ba4a1659335cd63b68483f2` remains the exact pin. + +Root owns a finite `Context.service(label, arguments, observe, project='a', +timeout=60)` adapter. It reuses hosted admission, explicit environment, +before/after runtime identities, selector stream limits, bounded in-memory +capture and owned process-group cleanup. The callback receives bounded live +snapshots and the original deadline, not an unrestricted process launcher. +Only literal loopback HTTP is admitted, without proxies or redirects, with a +five-second/request deadline, one MiB/body and at most 60 fixed API requests. +The whole research collector remains limited to 360 seconds. No SDK, ACP, +TypeScript, npm, alternate MCP fixture or direct fixture call is introduced. + +Root adds a separate real Git project C and supplies `ctx.native_probe`, built +from existing `repotests/testdata/agentplugins_native_probe` by exact Go 1.26.10. +Record compiler/probe identities; include the probe in immutable-file checks. +Projects A/B/C and outside cwd share the one original fresh HOME. The leaf owns +only benign uniquely named SKILL.md and `.kimi-code/mcp.json` entries in these +roots and an independent user marker. All authored paths remain ordinary, +single-link, bounded and outside alias traversal. MCP stdio commands select +the exact supplied probe, per-scope argv/cwd/events file and fresh nonce using +its existing `UAP_TEST_ROOT`, `UAP_TEST_EVENTS`, `UAP_TEST_NONCE` and +`UAP_TEST_REVISION` contract. Each entry sets documented startupTimeoutMs and +toolTimeoutMs to 3000; the fixed sequence uses at most 36 HTTP requests within +the shared ceiling of 60. No tool call is sent during this initial slice. + +The only native service argv is `kimi web --no-open --host 127.0.0.1 --port 0`. +The exact source accepts port zero and reports the bound port. With NO_COLOR=1, +require `Kimi server ready`, the complete line +` Local: http://127.0.0.1:/#token=` and a matching +` Token: ` line. The token is 43 base64url ASCII characters. +Read only original HOME's `.kimi-code/server.token`: ordinary same-UID parent +mode 0700, regular/single-link token mode 0600, exact 43 bytes, no-follow held +read with before/after identity. Its bytes must match both native banner fields. +Register any parsed token privately immediately. Unrecognized or incomplete +startup quarantines the raw streams; they must never enter a failure artifact. +Validated streams are redacted before admission. HTTP uses Authorization only; +never publish bearer-bearing fragments, query strings or exception text. + +Success JSON must be whole, duplicate-free, bounded, with integer `code:0`, +`msg:'success'`, bounded request_id and the following typed data. Other exits, +shapes and errors fail; only the two exact negative responses below are planned. + +| Native request | Required observation | +| --- | --- | +| `GET /api/v1/healthz`, no auth | HTTP 200, `data.ok:true`. | +| `GET /api/v1/meta`, no auth | HTTP 401 and exact code 40101; proves native bearer admission. | +| `GET /api/v1/meta`, bearer | `server_version:'2.3.2'`, nonempty server_id, ISO started_at, dangerous_bypass_auth false, backend v2, empty open_in_apps, and true websocket/file_upload/fs_query/mcp/tasks/terminal capabilities. Optional experimental_flags is a bool map; features contain typed name/state/meta; web_title is a string. | +| `POST /api/v1/workspaces` with exact root/name for A/B/C | Distinct IDs matching `wd_[a-z0-9._-]+_[0-9a-f]{12}`, exact canonical root/name, ISO created_at/last_opened_at and initial session_count zero. | +| `GET /api/v1/workspaces/{id}/trust` | Initially false for A/B/C. | +| `POST /api/v1/workspaces/{A-or-B}/trust` with `{}` then GET | Native true for A/B, C remains false. Perform before preservation baseline; never forge trust state or trust C. | +| `GET /api/v1/workspaces/{id}/skills` | Typed name/description/path/source rows select only the original-user and selected project research markers at exact SKILL.md paths. C skills may be visible: workspace trust gates MCP, not this catalog. | +| `GET /api/v2/mcp/servers?cwd=` | A/B contain user plus their own entry; C/outside contain only user. Require exact project `.kimi-code/mcp.json` origin, source global, mutable false, stdio command/argv/cwd and sorted env keys. User origin is original HOME's file with mutable true. Source global denotes a file layer, not user scope by itself. | +| `POST /api/v2/mcp/servers:test` with only `{name,cwd}` | A/B success true and native output identifies inspect_runtime; require fresh same-nonce/PID/session initialize and tools/list probe events in that request window. No inline server or direct fixture connection. C's named test returns HTTP 200 with exact code 40408 and no C probe events. | +| Repeat A/B/C catalogs, then `POST /api/v1/shutdown` with `{}` | Protected user/B/foreign bytes remain exact; shutdown data.ok is true. If the foreground CLI remains alive, send ordinary SIGTERM to the owned group and require exit zero, closed port and reaped group within five seconds. SIGKILL fallback is failed cleanup, never a successful case. | + +The source pin covers web shared.ts, persistentToken.ts, privateFiles.ts, +access-urls.ts, web/run.ts, rest-meta/meta, workspace/workspaces/skills, +routes/v2/mcp and shutdown routes. The web launcher passes CLI version 2.3.2 to +the server; the embedded server package version is not the reported CLI version. +New inert contracts must cover private-token quarantine/redaction, malformed +JSON/identity, wrong project origin, wrong probe nonce/session, the untrusted +negative and incomplete service cleanup. Preserve all qualification flags false. +Inspect genuine evidence before a separate two-round amendment admits the exact +product version set {2.3.1, 2.3.2}, provider tool calls or the final public UAP +lifecycle test `TestAgentpluginsKimiNativeProjectComponentsLifecycle`. + +## VS Code trusted development-host amendment + +Use the already pinned and observed 1.143.1 publisher, genuine Ubuntu 22.04, +ordinary-user/NNP/zero-capability/loopback namespace, strict cgroup, authenticated +Xvfb and normal Electron sandbox contract. Retain the existing untrusted mode. +Add focused `trusted_*_linux.go` files to the existing `vscodeworkspace` package +main and a closed request mode `trusted-project-v1`; absence of mode preserves +legacy labels, observer pins, budgets and behavior. Reuse that package's private +authority, sealing, capture, display and cleanup services directly. Do not copy +the controller, add a process primitive, disable trust/sandboxing or export a +new framework. Unknown modes, stages, paths and operations fail before launch. + +Reuse the dedicated publisher acquisition/materializer and its bounded parser. +Exact archive: `https://vscode.download.prss.microsoft.com/dbazure/download/stable/e646868227c3e3a9e3f24277c8c7220be42c0be7/code-stable-x64-1792691793.tar.gz`, +350,844,741 bytes, SHA256 +`48f658052e54e020a1c1be7b37ac0f9ae39f07e8ccda805c63f053cfda72b2be`. +Actual retained inventory: 4,262 members, 1,034,475,520 expanded bytes, +1,031,068,984 regular-file bytes, zero omitted symlinks. Do not increase the +generic extractor caps. Verify publisher `code` (223,685,880 bytes, +`cf8508cc7ddde30cfccc70caeda877a9a99119953c4476dcb30a3eb1a2c415e9`), +`resources/app/out/cli.js` (275,169 bytes, +`bd393ad6f0d28ba0aa7cd79cc685617f5187096f092009e315a4f098349f7976`), +and `resources/app/product.json` (68,251 bytes, +`a141a1de8ed44415c0c527b1882362e6abc25e674be052d67c09da71a27fbd7e`). +Keep ELF-plus-cli.js version/help preflight; ELECTRON_RUN_AS_NODE=1 is confined +to that fixed preflight and is absent from GUI execution. + +Freeze one minimal lock with the reviewed Node 24.21.0 archive and these packages: + +| Package | Version | Integrity | +| --- | --- | --- | +| @typescript/typescript-linux-x64 | 7.0.2 | sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A== | +| @types/node | 22.20.1 | sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q== | +| undici-types | 6.21.0 | sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== | +| playwright-core | 1.64.1 | sha512-BC4s8y6SEVA6Q1rSxZTto8hI1KUI3xXlHGZgvGqP4IqPdI/a6FX9H29IDNz7vKo9l21b6LfYosScPL6M3xxyDQ== | + +The 2026-10-26 continuation honors the owner's TypeScript 7.0.2 minimum. Use the +official Linux-x64 compiler package directly, with no wrapper or optional +platform fallback. Its exact regular `lib/tsc` is 24,101,026 bytes, SHA256 +`4f2de678286401759b3fb4475bafe35b8f32b4b3a07d92642bbf37eadc9b34a4`. +The official package integrity, binary identity and complete build-only library +closure are checked before and after compilation. This amendment received two +independent plan reviews; it does not change the old untrusted observer. +Use exact verified Node/npm distribution bytes and +`npm ci --ignore-scripts --no-audit --no-fund` in a temporary tool directory +before native network isolation. No ambient compiler/npm, lifecycle scripts or +browser downloads. Compile tracked TypeScript with the pinned `lib/tsc`, strict +ES2023/NodeNext and pinned types; emitted JS stays in the temporary build tree. +The VS Code declarations are build-only files from the exact publisher commit: +`vscode.d.ts` (742,500 bytes, Git blob `bd520cf7bb88454e99bd15da13c6b9c6ac56fd65`), +`vscode.proposed.chatPromptFiles.d.ts` (13,619 bytes, blob +`eb77adbd1a1084837ab2d7b8f669f8ecfc20f1b8`), and +`vscode.proposed.mcpServerDefinitions.d.ts` (3,302 bytes, blob +`81e75fe69d74e82bdfb4ca69d0e89b801e728118`). Fetch exact-commit raw source, +verify byte count and Git blob digest, and include it only in temporary compiler +inputs. No unpinned @types/vscode or emitted declaration runtime is introduced. +Vendor declarations may use skipLibCheck; our observer and driver remain strict. +playwright-core attaches to the publisher's Electron, never a substitute browser. +Seal the emitted driver/observer package manifests and module mode together +with the complete pinned playwright-core runtime JS/support-file closure; +TypeScript compilation does not bundle dependencies. Compiler/types stay in +the build directory, npm .bin links are excluded, and native execution must not +resolve modules from an unsealed tool cache or ambient node_modules. + +The trusted mode admits verified Node plus the sealed compiled UI driver through +the existing strict primitive. The driver starts the exact publisher using the +existing same-process isolation-verifier prelude. Its observed namespace must +match the driver, and its PID must match the spawned child before execve. +Fixed GUI argv: `code --new-window --disable-crash-reporter --locale en +--user-data-dir --extensions-dir +--extensionDevelopmentPath --extensionTestsPath /runner.js +--enable-proposed-api uap-research.project-runtime-observer +--remote-debugging-port=0 `. +Admit exactly one child-emitted `ws://127.0.0.1:<1024..65535>/devtools/browser/` +with no credentials/query/fragment or conflicting endpoint, and exactly one +corresponding workbench page. Attach inside the same namespace, with no fixed +port, outside-network, alternate-browser or generic-dialog fallback. + +Pinned source fixes the following finite UI grammar. Workspace startup title is +`Do you trust the authors of the files in this folder?`; click only +`Yes, I trust the authors` after matching the canonical folder in the details +and keeping `Trust the authors of all files in the parent folder '{name}'` +unchecked. Require the observer's exact folder and workspace.isTrusted true. +Trust A/B separately before preservation baselines; A must not implicitly trust B. +The separate `Trust Folder & Continue` flow is not an admitted fallback. + +The gateway broker uses errorOnUserInteraction, so start each owned MCP server +through native UI first: `MCP: List Servers`, `Select an MCP Server`, exact +fixture row, `Select action for '