From 92cbe3236e6b89554fbcafcb8163cac666363f11 Mon Sep 17 00:00:00 2001 From: Peter van Tol Date: Sat, 17 Oct 2026 10:12:32 +0200 Subject: [PATCH 01/10] fix: prove empty installed runtime before project composition --- .../forge-r58-projectless-idle-20261017.json | 16 +++ .../FORGE_SERVER_RUNTIME_LIFECYCLE_V1.md | 19 +++ forge/server_runtime.py | 22 +++ product-version.json | 2 +- .../qualify_installed_projectless_idle.py | 132 ++++++++++++++++++ tests/test_projectless_scheduler.py | 123 ++++++++++++++++ 6 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 .github/product-version-operations/forge-r58-projectless-idle-20261017.json create mode 100644 scripts/qualification/qualify_installed_projectless_idle.py create mode 100644 tests/test_projectless_scheduler.py diff --git a/.github/product-version-operations/forge-r58-projectless-idle-20261017.json b/.github/product-version-operations/forge-r58-projectless-idle-20261017.json new file mode 100644 index 00000000..47de2c51 --- /dev/null +++ b/.github/product-version-operations/forge-r58-projectless-idle-20261017.json @@ -0,0 +1,16 @@ +{ + "baseline_version": "2.22.0", + "classification_rationale": "L3-PROJECTLESS-INSTALLATION-IDLE-V1-20261017", + "component": "product", + "event_lineage": "L3-PROJECTLESS-INSTALLATION-IDLE-V1-20261017", + "expected_head": "523a13f3196c096da217421e74130df474fadcc6", + "operation_id": "forge-r58-projectless-idle-20261017", + "policy_revision": "forge-bootstrap-release-cadence-v2", + "product": "forge", + "projection_paths": "product-version.json", + "release_class": "PATCH", + "requested_bump": "patch", + "requested_version": null, + "schema_version": "1", + "target_version": "2.22.1" +} diff --git a/docs/architecture/FORGE_SERVER_RUNTIME_LIFECYCLE_V1.md b/docs/architecture/FORGE_SERVER_RUNTIME_LIFECYCLE_V1.md index b55b8cd6..1cc6854d 100644 --- a/docs/architecture/FORGE_SERVER_RUNTIME_LIFECYCLE_V1.md +++ b/docs/architecture/FORGE_SERVER_RUNTIME_LIFECYCLE_V1.md @@ -306,3 +306,22 @@ normal recovery. Its controller correction is a new exact source binding; the original 2.7.38 wheel and historical controlled-interruption evidence retain their identities. This matrix makes no host reboot, power-loss or installer acceptance claim. + +## Projectless installation idle (R58) + +A new installed instance can be scheduler `IDLE` before a project is selected. +The Server still requires its instance-owned provider readiness. Under the +canonical runtime mutation lease it opens a validated read-only storage snapshot +and proves absence of Mission state/allocation/intake/projection, submissions, +approved worksets, dispatcher/planning/bootstrap portfolio state, execution-host +bindings and immutable exchange audit. Only this narrow empty-work proof avoids +composing the project-bound execution runtime. Missing, corrupt, fenced or +unknown storage fails closed. Any retained work/history takes the existing +strict runtime path with all provider, project, EP-host and authority checks; +this change does not classify historical terminal records as an empty instance. + +Installation connectivity is still independently authenticated. Installation +service readiness is not project authorization or execution readiness. No +project, Mission, grant or repository is created by the empty probe. Each tick +rechecks storage under the shared lease; no cached empty classification survives +new work or restart. Runtime storage schema remains46. diff --git a/forge/server_runtime.py b/forge/server_runtime.py index c4462682..34ed00dd 100644 --- a/forge/server_runtime.py +++ b/forge/server_runtime.py @@ -1429,6 +1429,28 @@ def _tick(self) -> None: provider = self.services.provider_readiness() if not provider.get("ready"): raise ForgeServerRuntimeError("instance-owned planning provider is not ready") + # A fresh installation has no project execution context yet. Prove the + # narrow empty-work condition from one validated read-only snapshot, + # under the same lease used by Mission intake and scheduler mutation. + # Any work/history, unreadable store or uncertainty retains the normal + # strict composition below; no peer exception is treated as IDLE. + from .runtime.bootstrap import RuntimeBootstrap + with RuntimeServiceLock(self.root / "forge.db").acquire(): + database = RuntimeBootstrap(data_root=self.root, forge_version=canonical_version()).open_read_snapshot() + try: + work_tables = ("mission_state", "mission_id_allocations", "mission_intake_evidence", + "mission_runtime_projections", "scheduler_submissions", "approved_worksets", + "dispatcher_state", "planning_state", "bootstrap_portfolio_state", + "execution_host_bindings", "execution_host_exchange_audit") + empty = all(database._connection.execute(f"SELECT 1 FROM {table} LIMIT 1").fetchone() is None + for table in work_tables) + if empty: + if self.root_identity.drifted(): + raise ForgeServerRuntimeError("Forge Server selected instance root changed") + self.state.scheduler("IDLE") + return + finally: + database.close() with InstalledDynamicMissionRuntime.open(str(self.root), provider_id=self.provider_id) as runtime: service = ForgeRuntimeService(_ResumeOnlyLoop(runtime), runtime.states, runtime_database=runtime.database) tick = service.tick() diff --git a/product-version.json b/product-version.json index a405f931..ef004d8f 100644 --- a/product-version.json +++ b/product-version.json @@ -1,5 +1,5 @@ { "product": "forge", "schema_version": 1, - "version": "2.22.0" + "version": "2.22.1" } diff --git a/scripts/qualification/qualify_installed_projectless_idle.py b/scripts/qualification/qualify_installed_projectless_idle.py new file mode 100644 index 00000000..1d475011 --- /dev/null +++ b/scripts/qualification/qualify_installed_projectless_idle.py @@ -0,0 +1,132 @@ +"""Installed HTTP/restart proof; only external OS/keychain/Codex fixtures substituted.""" +import argparse +from hashlib import sha256 +from importlib.util import spec_from_file_location, module_from_spec +import json +import os +from pathlib import Path +import socket +import sqlite3 +import subprocess +import sys +from tempfile import TemporaryDirectory +import time +from unittest.mock import patch +from urllib.request import Request, urlopen +from urllib.error import HTTPError + +SOURCE=Path(__file__).resolve().parents[2] +TOKEN='synthetic-installation-only-token' +ADMIN='synthetic-forge-server-token' + + +def child(root,port): + from forge.secure_store import SecretState + from forge.server_runtime import ForgeServerRuntime + # External credential fixture, no actual Keychain read or write. + with patch('forge.installation_pairing.MacOSKeychainSecureStoreAdapter.resolve',return_value=(SecretState.RESOLVABLE,TOKEN)): + app=ForgeServerRuntime(data_root=root,credential_file=root/'server-credential',host='127.0.0.1',port=port,tick_interval=.05) + app.serve_forever() + + +def run(args): + spec=spec_from_file_location('projectless_installed_utils',SOURCE/'scripts/qualification/qualify_installed_http_successor.py') + utils=module_from_spec(spec);spec.loader.exec_module(utils) + artifact=utils._installed_wheel(args.wheel,source_revision=args.source_revision,verify_source=True) + from forge.ep_simulator import EpSimulatorState, EpSimulatorServer + from forge.runtime import RuntimeBootstrap + from forge.operator_identity import InstallationOperatorService, NamedOperatorIdentity + from forge.provider_security import (PlanningProviderSecurityService,ProviderAuthenticationMode, + CODEX_CLI_CHATGPT_SESSION_PROVIDER_TYPE,CODEX_CLI_CHATGPT_SESSION_TYPE) + from forge.provider_context import ProviderExecutionContextService + from forge.installation_pairing import InstallationPairingService + from forge.secure_store import SecretState + output=args.output_dir.resolve();output.mkdir(mode=0o700) + receipt={'qualification':'PROJECTLESS_INSTALLED_HTTP_IDLE_V1','source_revision':args.source_revision, + 'artifact':artifact,'result':'FAIL','cases':[],'cleanup':False, + 'limits':'Synthetic external Codex login/OS identity/Keychain; actual installed Forge scheduler, canonical storage, authenticated HTTP and separate Server OS restart. EP simulator only; no live installer, VM or real credentials.'} + try: + with TemporaryDirectory(prefix='forge-r58-') as scratch: + base=Path(scratch).resolve();root=base/'runtime' + db=RuntimeBootstrap(data_root=root,forge_version='qualification').open() + identity=NamedOperatorIdentity('synthetic-projectless-operator',os.getuid()) + operators=InstallationOperatorService(db,lambda:identity);context=operators.first_bind() + executable=base/'codex';executable.write_text('#!/bin/sh\nif [ "$1" = "--version" ]; then echo "codex-cli 0.153.4"; exit 0; fi\nif [ "$1" = "login" ] && [ "$2" = "status" ]; then echo "Logged in using ChatGPT"; exit 0; fi\nexit 7\n');executable.chmod(0o700) + class Store: + def status(self,reference):return SecretState.RESOLVABLE + PlanningProviderSecurityService(db,Store(),operators).configure(configuration_id='synthetic-codex',provider_id='codex-chatgpt-session',operator_context=context, + authentication_mode=ProviderAuthenticationMode.EXTERNAL_AUTHENTICATED_SESSION,provider_type=CODEX_CLI_CHATGPT_SESSION_PROVIDER_TYPE, + external_session_type=CODEX_CLI_CHATGPT_SESSION_TYPE,executable_path=str(executable),adapter_version='1.0',timeout_seconds=30, + input_token_bound=64000,context_token_bound=128000,output_token_bound=16000) + instance=db.runtime_identity.runtime_id;db.close() + home=base/'provider-home';home.mkdir();config=base/'provider-config';config.mkdir() + ProviderExecutionContextService(root).configure(provider_id='codex-chatgpt-session',provider_type=CODEX_CLI_CHATGPT_SESSION_PROVIDER_TYPE, + executable_path=str(executable),provider_home=str(home),provider_config_home=str(config)) + credential=root/'server-credential';credential.write_text(ADMIN);credential.chmod(0o600) + state=EpSimulatorState(bearer_token=TOKEN) + ep=EpSimulatorServer(state);original=ep.server.RequestHandlerClass;reads=[] + class Handler(original): + def do_GET(self): + if self.path!='/v1/installation-compatibility':return super().do_GET() + if self.headers.get('Authorization')!='Bearer '+TOKEN or self.headers.get('EP-Instance-ID')!='synthetic-installation-ep' or self.headers.get('Forge-Instance-ID')!=instance: + return self._error(401,'AUTHENTICATION_REQUIRED') + reads.append('installation') + value=dict(contract_version='1.0',instance={'id':'synthetic-installation-ep'},producer={'id':'engineering-platform','version':'synthetic'}, + authentication=dict(binding_id='installation',ep_instance_id='synthetic-installation-ep',forge_instance_id=instance,consumer_id='synthetic-consumer',purpose='INSTALLATION_READBACK'), + authority=dict(installation_readback=True,project_access=False,submission=False,execution=False,governance=False)) + raw=json.dumps(value).encode();self.send_response(200);self.send_header('EP-Server-Instance','synthetic-installation-ep');self.send_header('Content-Length',str(len(raw)));self.end_headers();self.wfile.write(raw) + ep.server.RequestHandlerClass=Handler + with ep: + with patch('forge.operator_identity.MacOSGeneratedUIDIdentityAdapter.resolve',return_value=identity): + InstallationPairingService(root).configure(operation_id='synthetic-installation',binding_id='installation',endpoint=ep.base_url, + ep_instance_id='synthetic-installation-ep',consumer_id='synthetic-consumer',credential_reference='keychain://synthetic/installation',allow_loopback_http=True) + for case in ('initial','restart','uncertain-work'): + if case=='uncertain-work': + db=RuntimeBootstrap(data_root=root,forge_version='qualification').open() + db.save_dispatcher_state(status='ACTIVE',mission_sequence=('synthetic-uncertain',),active_mission_id='synthetic-uncertain');db.close() + with socket.socket() as probe:probe.bind(('127.0.0.1',0));port=probe.getsockname()[1] + log=output/(case+'.private.log') + with log.open('xb') as stream: + process=subprocess.Popen([sys.executable,'-I',str(Path(__file__).resolve()),'--child','--root',str(root),'--port',str(port)],cwd=base,stdout=stream,stderr=stream) + try: + deadline=time.monotonic()+15;body=None + while time.monotonic() Date: Sat, 17 Oct 2026 10:13:50 +0200 Subject: [PATCH 02/10] ci: require installed projectless readiness before release --- .github/workflows/ci.yml | 17 +++++++++++++++++ .github/workflows/forge-production-release.yml | 6 ++++++ 2 files changed, 23 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89aa17df..652b81fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,6 +53,23 @@ jobs: name: forge-genesis-bootstrap-${{ github.sha }} path: ${{ runner.temp }}/forge-genesis-proof/*.public.json if-no-files-found: error + - name: Projectless installed scheduler HTTP and restart + timeout-minutes: 3 + run: | + set -euo pipefail + wheel=("$RUNNER_TEMP"/forge-genesis-wheel/forge_autonomy-*.whl) + test "${#wheel[@]}" -eq 1 + cd "$RUNNER_TEMP" + "$RUNNER_TEMP/forge-genesis-installed/bin/python" -I \ + "$GITHUB_WORKSPACE/scripts/qualification/qualify_installed_projectless_idle.py" \ + --wheel "${wheel[0]}" --source-revision "$(git -C "$GITHUB_WORKSPACE" rev-parse HEAD)" \ + --output-dir "$RUNNER_TEMP/forge-projectless-idle" + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + if: always() + with: + name: forge-projectless-idle-${{ github.sha }} + path: ${{ runner.temp }}/forge-projectless-idle/installed-projectless-idle.public.json + if-no-files-found: error - run: bash scripts/validate.sh env: FORGE_WITH_COVERAGE: "1" diff --git a/.github/workflows/forge-production-release.yml b/.github/workflows/forge-production-release.yml index 1811d0c7..6677fc12 100644 --- a/.github/workflows/forge-production-release.yml +++ b/.github/workflows/forge-production-release.yml @@ -93,6 +93,12 @@ jobs: PYTHONNOUSERSITE=1 PYTHONSAFEPATH=1 "$RUNNER_TEMP/forge-wheel/bin/python" -I -c 'import forge, pathlib, tempfile; from importlib.metadata import version; from forge._version import canonical_version; from forge.qualification.installed_smoke import run, assert_runtime_persistence; assert version("forge-autonomy") == canonical_version() == __import__("os").environ["VERSION"]; assert "/site-packages/forge/" in str(pathlib.Path(forge.__file__).resolve()); run(); root=tempfile.TemporaryDirectory(); workspace=pathlib.Path(root.name)/"workspace"; workspace.mkdir(); assert_runtime_persistence(str(workspace), str(pathlib.Path(root.name)/"runtime"), canonical_version()); root.cleanup()' "$RUNNER_TEMP/forge-wheel/bin/python" -I "$GITHUB_WORKSPACE/scripts/qualification/qualify_installed_installation_detach.py" --wheel "$GITHUB_WORKSPACE/dist/forge_autonomy-$VERSION-py3-none-any.whl" --source-revision "$SOURCE_SHA" --output-dir "$RUNNER_TEMP/forge-installation-detach-wheel" cp "$RUNNER_TEMP/forge-installation-detach-wheel/installed-installation-detach.public.json" "$GITHUB_WORKSPACE/dist/installed-installation-detach-qualified.json" + "$RUNNER_TEMP/forge-wheel/bin/python" -I \ + "$GITHUB_WORKSPACE/scripts/qualification/qualify_installed_projectless_idle.py" \ + --wheel "$GITHUB_WORKSPACE/dist/forge_autonomy-$VERSION-py3-none-any.whl" \ + --source-revision "$SOURCE_SHA" --output-dir "$RUNNER_TEMP/forge-projectless-idle-wheel" + cp "$RUNNER_TEMP/forge-projectless-idle-wheel/installed-projectless-idle.public.json" \ + "$GITHUB_WORKSPACE/dist/installed-projectless-idle-qualified.json" "$RUNNER_TEMP/forge-wheel/bin/forge" --help >/dev/null test "$("$RUNNER_TEMP/forge-wheel/bin/forge" --version)" = "$VERSION" "$RUNNER_TEMP/forge-wheel/bin/python" -I -m forge.qualification.criterion_completion --output-dir "$RUNNER_TEMP/forge-criterion-wheel" From 84d71427e5e7eece4bea49861341c1de1006ce32 Mon Sep 17 00:00:00 2001 From: Peter van Tol Date: Sat, 17 Oct 2026 10:14:18 +0200 Subject: [PATCH 03/10] test: prove installed resumable Mission still requires project peer --- .../qualify_installed_projectless_idle.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/scripts/qualification/qualify_installed_projectless_idle.py b/scripts/qualification/qualify_installed_projectless_idle.py index 1d475011..9a0f8e35 100644 --- a/scripts/qualification/qualify_installed_projectless_idle.py +++ b/scripts/qualification/qualify_installed_projectless_idle.py @@ -80,7 +80,12 @@ def do_GET(self): with patch('forge.operator_identity.MacOSGeneratedUIDIdentityAdapter.resolve',return_value=identity): InstallationPairingService(root).configure(operation_id='synthetic-installation',binding_id='installation',endpoint=ep.base_url, ep_instance_id='synthetic-installation-ep',consumer_id='synthetic-consumer',credential_reference='keychain://synthetic/installation',allow_loopback_http=True) - for case in ('initial','restart','uncertain-work'): + for case in ('initial','restart','resumable-work','uncertain-work'): + if case=='resumable-work': + from forge.state import MissionStateStore + db=RuntimeBootstrap(data_root=root,forge_version='qualification').open() + try:MissionStateStore(db,data_root=str(root)).create({'id':'synthetic-resume'},[{'id':'intent'}],[{'id':'action'}],occurred_at='2026-10-17T00:00:00Z') + finally:db.close() if case=='uncertain-work': db=RuntimeBootstrap(data_root=root,forge_version='qualification').open() db.save_dispatcher_state(status='ACTIVE',mission_sequence=('synthetic-uncertain',),active_mission_id='synthetic-uncertain');db.close() @@ -98,22 +103,24 @@ def do_GET(self): with urlopen(request,timeout=2) as response:body=json.load(response) except HTTPError as error: with error:body=json.load(error) - wanted='NOT_READY' if case=='uncertain-work' else 'IDLE' + wanted='IDLE' if case in ('initial','restart') else 'NOT_READY' if body['scheduler']['state']==wanted:break except OSError:pass time.sleep(.05) assert body is not None and body['scheduler']['state']==wanted assert body['provider']['ready'] and body['component_connected'] - assert body['service_ready']==(case!='uncertain-work') and body['ready']==(case!='uncertain-work') + assert body['service_ready']==(case in ('initial','restart')) and body['ready']==(case in ('initial','restart')) + if case=='resumable-work':assert body['scheduler']['last_error']=='PeerConfigurationError' assert body['execution_ready'] is False and body['project_authorized'] is False - receipt['cases'].append({'case':case,'scheduler':wanted,'service_ready':body['service_ready'],'component_connected':body['component_connected'],'pid':process.pid}) + receipt['cases'].append({'case':case,'scheduler':wanted,'service_ready':body['service_ready'],'component_connected':body['component_connected'],'last_error':body['scheduler']['last_error'],'pid':process.pid}) finally: process.terminate() try:process.wait(timeout=8) except subprocess.TimeoutExpired:process.kill();process.wait(timeout=3);raise assert process.returncode==0 with sqlite3.connect(root/'forge.db') as db: - for table in ('mission_state','mission_id_allocations','execution_host_peer_configuration','scheduler_submissions'): + assert db.execute('SELECT count(*) FROM mission_state').fetchone()[0]==1 + for table in ('mission_id_allocations','execution_host_peer_configuration','scheduler_submissions'): assert db.execute(f'SELECT count(*) FROM {table}').fetchone()[0]==0 assert reads receipt['installation_http_reads']=len(reads) From 65db8abd4d3f05d03611dc6440d563f2d13205cd Mon Sep 17 00:00:00 2001 From: Peter van Tol Date: Sat, 17 Oct 2026 10:14:50 +0200 Subject: [PATCH 04/10] test: preserve synthetic owner identity across installed Server restart --- scripts/qualification/qualify_installed_projectless_idle.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/qualification/qualify_installed_projectless_idle.py b/scripts/qualification/qualify_installed_projectless_idle.py index 9a0f8e35..6c245f8a 100644 --- a/scripts/qualification/qualify_installed_projectless_idle.py +++ b/scripts/qualification/qualify_installed_projectless_idle.py @@ -22,9 +22,10 @@ def child(root,port): from forge.secure_store import SecretState + from forge.operator_identity import NamedOperatorIdentity from forge.server_runtime import ForgeServerRuntime # External credential fixture, no actual Keychain read or write. - with patch('forge.installation_pairing.MacOSKeychainSecureStoreAdapter.resolve',return_value=(SecretState.RESOLVABLE,TOKEN)): + with patch('forge.installation_pairing.MacOSKeychainSecureStoreAdapter.resolve',return_value=(SecretState.RESOLVABLE,TOKEN)), patch('forge.operator_identity.MacOSGeneratedUIDIdentityAdapter.resolve',return_value=NamedOperatorIdentity('synthetic-projectless-operator',os.getuid())): app=ForgeServerRuntime(data_root=root,credential_file=root/'server-credential',host='127.0.0.1',port=port,tick_interval=.05) app.serve_forever() @@ -107,6 +108,7 @@ def do_GET(self): if body['scheduler']['state']==wanted:break except OSError:pass time.sleep(.05) + if body is not None:receipt['last_observed_scheduler']=body['scheduler'] assert body is not None and body['scheduler']['state']==wanted assert body['provider']['ready'] and body['component_connected'] assert body['service_ready']==(case in ('initial','restart')) and body['ready']==(case in ('initial','restart')) From f60f4186457d577c51c7bf45832b1d1b732dbf3e Mon Sep 17 00:00:00 2001 From: Peter van Tol Date: Sat, 17 Oct 2026 10:17:12 +0200 Subject: [PATCH 05/10] test: isolate uncertain-only installed runtime from Mission fixture --- .../qualify_installed_projectless_idle.py | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/scripts/qualification/qualify_installed_projectless_idle.py b/scripts/qualification/qualify_installed_projectless_idle.py index 6c245f8a..c6afe21d 100644 --- a/scripts/qualification/qualify_installed_projectless_idle.py +++ b/scripts/qualification/qualify_installed_projectless_idle.py @@ -48,22 +48,29 @@ def run(args): 'limits':'Synthetic external Codex login/OS identity/Keychain; actual installed Forge scheduler, canonical storage, authenticated HTTP and separate Server OS restart. EP simulator only; no live installer, VM or real credentials.'} try: with TemporaryDirectory(prefix='forge-r58-') as scratch: - base=Path(scratch).resolve();root=base/'runtime' - db=RuntimeBootstrap(data_root=root,forge_version='qualification').open() + def initialize(base): + base.mkdir(parents=True,exist_ok=True) + root=base/'runtime' + db=RuntimeBootstrap(data_root=root,forge_version='qualification').open() + identity=NamedOperatorIdentity('synthetic-projectless-operator',os.getuid()) + operators=InstallationOperatorService(db,lambda:identity);context=operators.first_bind() + executable=base/'codex';executable.write_text('#!/bin/sh\nif [ "$1" = "--version" ]; then echo "codex-cli 0.153.4"; exit 0; fi\nif [ "$1" = "login" ] && [ "$2" = "status" ]; then echo "Logged in using ChatGPT"; exit 0; fi\nexit 7\n');executable.chmod(0o700) + class Store: + def status(self,reference):return SecretState.RESOLVABLE + PlanningProviderSecurityService(db,Store(),operators).configure(configuration_id='synthetic-codex',provider_id='codex-chatgpt-session',operator_context=context, + authentication_mode=ProviderAuthenticationMode.EXTERNAL_AUTHENTICATED_SESSION,provider_type=CODEX_CLI_CHATGPT_SESSION_PROVIDER_TYPE, + external_session_type=CODEX_CLI_CHATGPT_SESSION_TYPE,executable_path=str(executable),adapter_version='1.0',timeout_seconds=30, + input_token_bound=64000,context_token_bound=128000,output_token_bound=16000) + instance=db.runtime_identity.runtime_id;db.close() + home=base/'provider-home';home.mkdir();config=base/'provider-config';config.mkdir() + ProviderExecutionContextService(root).configure(provider_id='codex-chatgpt-session',provider_type=CODEX_CLI_CHATGPT_SESSION_PROVIDER_TYPE, + executable_path=str(executable),provider_home=str(home),provider_config_home=str(config)) + credential=root/'server-credential';credential.write_text(ADMIN);credential.chmod(0o600) + return root,instance + base=Path(scratch).resolve() identity=NamedOperatorIdentity('synthetic-projectless-operator',os.getuid()) - operators=InstallationOperatorService(db,lambda:identity);context=operators.first_bind() - executable=base/'codex';executable.write_text('#!/bin/sh\nif [ "$1" = "--version" ]; then echo "codex-cli 0.153.4"; exit 0; fi\nif [ "$1" = "login" ] && [ "$2" = "status" ]; then echo "Logged in using ChatGPT"; exit 0; fi\nexit 7\n');executable.chmod(0o700) - class Store: - def status(self,reference):return SecretState.RESOLVABLE - PlanningProviderSecurityService(db,Store(),operators).configure(configuration_id='synthetic-codex',provider_id='codex-chatgpt-session',operator_context=context, - authentication_mode=ProviderAuthenticationMode.EXTERNAL_AUTHENTICATED_SESSION,provider_type=CODEX_CLI_CHATGPT_SESSION_PROVIDER_TYPE, - external_session_type=CODEX_CLI_CHATGPT_SESSION_TYPE,executable_path=str(executable),adapter_version='1.0',timeout_seconds=30, - input_token_bound=64000,context_token_bound=128000,output_token_bound=16000) - instance=db.runtime_identity.runtime_id;db.close() - home=base/'provider-home';home.mkdir();config=base/'provider-config';config.mkdir() - ProviderExecutionContextService(root).configure(provider_id='codex-chatgpt-session',provider_type=CODEX_CLI_CHATGPT_SESSION_PROVIDER_TYPE, - executable_path=str(executable),provider_home=str(home),provider_config_home=str(config)) - credential=root/'server-credential';credential.write_text(ADMIN);credential.chmod(0o600) + root,instance=initialize(base/'primary') + primary_root=root state=EpSimulatorState(bearer_token=TOKEN) ep=EpSimulatorServer(state);original=ep.server.RequestHandlerClass;reads=[] class Handler(original): @@ -88,6 +95,10 @@ def do_GET(self): try:MissionStateStore(db,data_root=str(root)).create({'id':'synthetic-resume'},[{'id':'intent'}],[{'id':'action'}],occurred_at='2026-10-17T00:00:00Z') finally:db.close() if case=='uncertain-work': + root,instance=initialize(base/'uncertain-only') + assert root!=primary_root + with patch('forge.operator_identity.MacOSGeneratedUIDIdentityAdapter.resolve',return_value=identity): + InstallationPairingService(root).configure(operation_id='synthetic-installation',binding_id='installation',endpoint=ep.base_url,ep_instance_id='synthetic-installation-ep',consumer_id='synthetic-consumer',credential_reference='keychain://synthetic/installation',allow_loopback_http=True) db=RuntimeBootstrap(data_root=root,forge_version='qualification').open() db.save_dispatcher_state(status='ACTIVE',mission_sequence=('synthetic-uncertain',),active_mission_id='synthetic-uncertain');db.close() with socket.socket() as probe:probe.bind(('127.0.0.1',0));port=probe.getsockname()[1] @@ -114,16 +125,18 @@ def do_GET(self): assert body['service_ready']==(case in ('initial','restart')) and body['ready']==(case in ('initial','restart')) if case=='resumable-work':assert body['scheduler']['last_error']=='PeerConfigurationError' assert body['execution_ready'] is False and body['project_authorized'] is False - receipt['cases'].append({'case':case,'scheduler':wanted,'service_ready':body['service_ready'],'component_connected':body['component_connected'],'last_error':body['scheduler']['last_error'],'pid':process.pid}) + receipt['cases'].append({'case':case,'scheduler':wanted,'service_ready':body['service_ready'],'component_connected':body['component_connected'],'last_error':body['scheduler']['last_error'],'instance_id':body['instance_id'],'pid':process.pid}) finally: process.terminate() try:process.wait(timeout=8) except subprocess.TimeoutExpired:process.kill();process.wait(timeout=3);raise assert process.returncode==0 with sqlite3.connect(root/'forge.db') as db: - assert db.execute('SELECT count(*) FROM mission_state').fetchone()[0]==1 + assert db.execute('SELECT count(*) FROM mission_state').fetchone()[0]==0 + assert db.execute('SELECT count(*) FROM dispatcher_state').fetchone()[0]==1 for table in ('mission_id_allocations','execution_host_peer_configuration','scheduler_submissions'): assert db.execute(f'SELECT count(*) FROM {table}').fetchone()[0]==0 + assert receipt['cases'][2]['instance_id']!=receipt['cases'][3]['instance_id'] assert reads receipt['installation_http_reads']=len(reads) receipt['result']='PASS' From c083f555e66f9d6898dba043be6758b23f42a1fc Mon Sep 17 00:00:00 2001 From: Peter van Tol Date: Sat, 17 Oct 2026 11:09:29 +0200 Subject: [PATCH 06/10] test: retain closed single-flight failure facts and controlled late-start proof --- .../qualify_installed_http_successor.py | 45 ++++++++++++++++++- .../test_installed_concurrency_diagnostics.py | 26 +++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 tests/test_installed_concurrency_diagnostics.py diff --git a/scripts/qualification/qualify_installed_http_successor.py b/scripts/qualification/qualify_installed_http_successor.py index dbdaa82d..3810963b 100644 --- a/scripts/qualification/qualify_installed_http_successor.py +++ b/scripts/qualification/qualify_installed_http_successor.py @@ -1283,6 +1283,20 @@ def _phase(root: Path, scenario: str, phase: str, endpoint: str) -> None: if time.monotonic() >= deadline: raise RuntimeError("concurrent start barrier timed out") time.sleep(0.01) + if (root / "controlled-late-start.private").exists(): + original_preflight = runtime.preflight + def controlled_preflight(*args, **kwargs): + result = original_preflight(*args, **kwargs) + marker = root / ("race-start-b.preflight.private" if phase == "race-start-a" else "race-start-a.finished.private") + if phase == "race-start-b": + (root / "race-start-b.preflight.private").write_text("observed") + control_deadline = time.monotonic() + 20 + while not marker.exists(): + if time.monotonic() >= control_deadline: + raise RuntimeError("controlled late-start barrier timed out") + time.sleep(0.01) + return result + runtime.preflight = controlled_preflight try: runtime.start(mission_id, _initial_truth()) except Exception as error: @@ -1291,6 +1305,9 @@ def _phase(root: Path, scenario: str, phase: str, endpoint: str) -> None: }) else: fixture._write(root / f"{phase}.race.private.json", {"result": "STARTED"}) + finally: + if phase == "race-start-a": + (root / "race-start-a.finished.private").write_text("finished") elif phase == "after-a-cut": def before_successor() -> bool: observed = runtime.states.get(mission_id) @@ -2512,6 +2529,23 @@ def _scenario(root: Path, scenario: str, wheel: Path, *, observer=None) -> dict: **({"recovery": recovery_summary} if recovery_summary is not None else {})} +def _concurrent_observation(outcomes, submissions, invocations): + """Closed public facts, excluding arbitrary exception messages and paths.""" + from forge.state import MissionExecutionStatus + known_types = {"RuntimeServiceBusy", "MissionStateStoreError", "InstalledDynamicMissionError"} + known_reasons = { + "canonical runtime is busy": "RUNTIME_BUSY", + "public start requires a canonically admitted zero-Action Mission": "NOT_ZERO_ACTION", + **{f"mission state transition {state.value} -> CREATED is not permitted": + "TRANSITION_" + state.value + "_TO_CREATED_DENIED" for state in MissionExecutionStatus}, + } + return {"outcomes": [{"result": item.get("result") if item.get("result") in {"STARTED", "REJECTED"} else "UNKNOWN", + "type": item.get("type") if item.get("type") in known_types else "OTHER", + "reason_code": known_reasons.get(item.get("reason"), "UNCLASSIFIED")} + for item in outcomes], + "submission_count": submissions, "planner_invocation_count": invocations} + + def _concurrent_start_case(root: Path, wheel: Path) -> dict: """Race two installed Forge processes at the public zero-Action start gate.""" root.mkdir() @@ -2578,7 +2612,10 @@ def _concurrent_start_case(root: Path, wheel: Path) -> dict: or rejection.get("reason") != expected_rejections.get(rejection.get("type")) or len(simulator.submission_ids()) != 1 or len(fixture._read(root / "provider-inputs.private.json")) != 1): - raise RuntimeError("concurrent starters crossed the single-flight Action boundary") + error = RuntimeError("concurrent starters crossed the single-flight Action boundary") + error.single_flight_observation = _concurrent_observation( + outcomes, len(simulator.submission_ids()), len(fixture._read(root / "provider-inputs.private.json"))) + raise error submission_id = simulator.submission_ids()[0] payload = simulator.submitted_payload(submission_id) pending = validate_fixture( @@ -2743,6 +2780,7 @@ def main() -> int: parser.add_argument("--output-dir", required=True, type=Path) parser.add_argument("--source-revision") parser.add_argument("--scenario", choices=SCENARIOS) + parser.add_argument("--late-start-control", action="store_true") parser.add_argument("--governance-case", choices=GOVERNANCE_CASES) parser.add_argument("--preflight-case", choices=tuple(PREFLIGHT_CASES)) parser.add_argument("--provider-case", choices=PROVIDER_CASES) @@ -2942,6 +2980,9 @@ def main() -> int: for scenario in scenarios: try: if scenario == "concurrent-start": + if args.late_start_control: + (root / scenario).mkdir(parents=True, exist_ok=True) + (root / scenario / "controlled-late-start.private").write_text("fixture-only") summaries.append(_with_case_cleanup( root / scenario, _concurrent_start_case, args.wheel.resolve(), )) @@ -2957,6 +2998,8 @@ def main() -> int: for frame in traceback.extract_tb(error.__traceback__)], "stage_trace": fixture._read( root / scenario / "stage-trace.public.json", [])}) + if scenario == "concurrent-start" and hasattr(error, "single_flight_observation"): + report["failure"]["single_flight"] = error.single_flight_observation fixture._write(root / "installed-http-successor.public.json", report) print(json.dumps(report, sort_keys=True)) return 1 diff --git a/tests/test_installed_concurrency_diagnostics.py b/tests/test_installed_concurrency_diagnostics.py new file mode 100644 index 00000000..8f359b6a --- /dev/null +++ b/tests/test_installed_concurrency_diagnostics.py @@ -0,0 +1,26 @@ +"""Closed diagnostics never turn a duplicate-effect observation into acceptance.""" +import importlib.util +import json +from pathlib import Path +import unittest + +spec=importlib.util.spec_from_file_location('r58_concurrency_qualifier',Path(__file__).parents[1]/'scripts/qualification/qualify_installed_http_successor.py') +module=importlib.util.module_from_spec(spec);spec.loader.exec_module(module) + + +class ConcurrentDiagnosticsTests(unittest.TestCase): + def test_late_transition_is_observed_without_changing_acceptance(self): + value=module._concurrent_observation([{'result':'REJECTED','type':'MissionStateStoreError','reason':'mission state transition WAITING_FOR_EXECUTION -> CREATED is not permitted'},{'result':'STARTED'}],1,1) + self.assertEqual(value['outcomes'][0]['reason_code'],'TRANSITION_WAITING_FOR_EXECUTION_TO_CREATED_DENIED') + self.assertEqual((value['submission_count'],value['planner_invocation_count']),(1,1)) + + def test_unknown_exception_text_and_identifiers_are_never_published(self): + value=module._concurrent_observation([{'result':'private-token','type':'/private/secret-path','reason':'Bearer private-token','actor':'private-actor'}],2,3) + raw=json.dumps(value) + for secret in ('private-token','secret-path','Bearer','private-actor'):self.assertNotIn(secret,raw) + self.assertEqual(value['outcomes'][0],{'result':'UNKNOWN','type':'OTHER','reason_code':'UNCLASSIFIED'}) + + def test_busy_and_duplicate_effect_counts_remain_exact_observations(self): + value=module._concurrent_observation([{'result':'REJECTED','type':'RuntimeServiceBusy','reason':'canonical runtime is busy'}],2,2) + self.assertEqual(value['outcomes'][0]['reason_code'],'RUNTIME_BUSY') + self.assertEqual((value['submission_count'],value['planner_invocation_count']),(2,2)) From 7fbe32d98bb0b37e9f7f1f83016477f5e5b40906 Mon Sep 17 00:00:00 2001 From: Peter van Tol Date: Sat, 17 Oct 2026 11:09:59 +0200 Subject: [PATCH 07/10] test: create late-start marker within owned case directory --- .../qualification/qualify_installed_http_successor.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/scripts/qualification/qualify_installed_http_successor.py b/scripts/qualification/qualify_installed_http_successor.py index 3810963b..1f1a57e9 100644 --- a/scripts/qualification/qualify_installed_http_successor.py +++ b/scripts/qualification/qualify_installed_http_successor.py @@ -2546,9 +2546,11 @@ def _concurrent_observation(outcomes, submissions, invocations): "submission_count": submissions, "planner_invocation_count": invocations} -def _concurrent_start_case(root: Path, wheel: Path) -> dict: +def _concurrent_start_case(root: Path, wheel: Path, late_start_control: bool = False) -> dict: """Race two installed Forge processes at the public zero-Action start gate.""" root.mkdir() + if late_start_control: + (root / "controlled-late-start.private").write_text("fixture-only") fixture._write(root / "artifact-a.json", { "report": {"fields": ["report_data"]}, "policy": {"authorization_required": True}, @@ -2980,11 +2982,8 @@ def main() -> int: for scenario in scenarios: try: if scenario == "concurrent-start": - if args.late_start_control: - (root / scenario).mkdir(parents=True, exist_ok=True) - (root / scenario / "controlled-late-start.private").write_text("fixture-only") summaries.append(_with_case_cleanup( - root / scenario, _concurrent_start_case, args.wheel.resolve(), + root / scenario, _concurrent_start_case, args.wheel.resolve(), args.late_start_control, )) else: summaries.append(_with_case_cleanup( From ffaa5efd7acfbec288242be48a1b900c9e451bb5 Mon Sep 17 00:00:00 2001 From: Peter van Tol Date: Sat, 17 Oct 2026 11:11:11 +0200 Subject: [PATCH 08/10] test: recognize exact canonical late-start fence with single-flight invariants --- .../qualify_installed_http_successor.py | 30 ++++++++++++------- .../test_installed_concurrency_diagnostics.py | 12 ++++++++ 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/scripts/qualification/qualify_installed_http_successor.py b/scripts/qualification/qualify_installed_http_successor.py index 1f1a57e9..2f9a6a7a 100644 --- a/scripts/qualification/qualify_installed_http_successor.py +++ b/scripts/qualification/qualify_installed_http_successor.py @@ -2529,6 +2529,22 @@ def _scenario(root: Path, scenario: str, wheel: Path, *, observer=None) -> dict: **({"recovery": recovery_summary} if recovery_summary is not None else {})} +def _concurrent_accepted(outcomes, submissions, invocations): + """One actual winner, one exact canonical refusal, and one original effect.""" + expected = { + "RuntimeServiceBusy": ("canonical runtime is busy",), + "MissionStateStoreError": ( + "mission state transition CREATED -> CREATED is not permitted", + "mission state transition WAITING_FOR_EXECUTION -> CREATED is not permitted", + ), + "InstalledDynamicMissionError": ("public start requires a canonically admitted zero-Action Mission",), + } + rejection = next((item for item in outcomes if item.get("result") == "REJECTED"), {}) + return (sorted(item.get("result", "UNKNOWN") for item in outcomes) == ["REJECTED", "STARTED"] + and rejection.get("reason") in expected.get(rejection.get("type"), ()) + and submissions == 1 and invocations == 1) + + def _concurrent_observation(outcomes, submissions, invocations): """Closed public facts, excluding arbitrary exception messages and paths.""" from forge.state import MissionExecutionStatus @@ -2604,16 +2620,8 @@ def _concurrent_start_case(root: Path, wheel: Path, late_start_control: bool = F handle.close() outcomes = [fixture._read(root / f"{phase}.race.private.json") for phase in ("race-start-a", "race-start-b")] - rejection = next((item for item in outcomes if item["result"] == "REJECTED"), {}) - expected_rejections = { - RuntimeServiceBusy.__name__: "canonical runtime is busy", - MissionStateStoreError.__name__: "mission state transition CREATED -> CREATED is not permitted", - InstalledDynamicMissionError.__name__: "public start requires a canonically admitted zero-Action Mission", - } - if (sorted(item["result"] for item in outcomes) != ["REJECTED", "STARTED"] - or rejection.get("reason") != expected_rejections.get(rejection.get("type")) - or len(simulator.submission_ids()) != 1 - or len(fixture._read(root / "provider-inputs.private.json")) != 1): + if not _concurrent_accepted(outcomes, len(simulator.submission_ids()), + len(fixture._read(root / "provider-inputs.private.json"))): error = RuntimeError("concurrent starters crossed the single-flight Action boundary") error.single_flight_observation = _concurrent_observation( outcomes, len(simulator.submission_ids()), len(fixture._read(root / "provider-inputs.private.json"))) @@ -2799,6 +2807,8 @@ def main() -> int: "preflight-stage", "preflight-first", "preflight-repeat")) parser.add_argument("--endpoint") args = parser.parse_args() + if args.late_start_control and (args.scenario != "concurrent-start" or args.phase is not None): + parser.error("late-start control requires only the concurrent-start parent case") if args.source_revision is not None and ( len(args.source_revision) != 40 or any(character not in "0123456789abcdef" for character in args.source_revision) ): diff --git a/tests/test_installed_concurrency_diagnostics.py b/tests/test_installed_concurrency_diagnostics.py index 8f359b6a..ccf1830e 100644 --- a/tests/test_installed_concurrency_diagnostics.py +++ b/tests/test_installed_concurrency_diagnostics.py @@ -24,3 +24,15 @@ def test_busy_and_duplicate_effect_counts_remain_exact_observations(self): value=module._concurrent_observation([{'result':'REJECTED','type':'RuntimeServiceBusy','reason':'canonical runtime is busy'}],2,2) self.assertEqual(value['outcomes'][0]['reason_code'],'RUNTIME_BUSY') self.assertEqual((value['submission_count'],value['planner_invocation_count']),(2,2)) + + def test_exact_observed_late_canonical_refusal_is_still_one_winner(self): + outcomes=[{'result':'STARTED'},{'result':'REJECTED','type':'MissionStateStoreError','reason':'mission state transition WAITING_FOR_EXECUTION -> CREATED is not permitted'}] + self.assertTrue(module._concurrent_accepted(outcomes,1,1)) + for counts in ((2,1),(1,2),(0,1),(1,0)): + self.assertFalse(module._concurrent_accepted(outcomes,*counts)) + + def test_other_transitions_untyped_errors_and_two_winners_stay_red(self): + for typ,reason in [('MissionStateStoreError','mission state transition FAILED -> CREATED is not permitted'),('RuntimeError','canonical runtime is busy'),('MissionStateStoreError','unrelated storage error')]: + self.assertFalse(module._concurrent_accepted([{'result':'STARTED'},{'result':'REJECTED','type':typ,'reason':reason}],1,1)) + self.assertFalse(module._concurrent_accepted([{'result':'STARTED'},{'result':'STARTED'}],1,1)) + self.assertFalse(module._concurrent_accepted([{'result':'REJECTED'},{'result':'REJECTED'}],1,1)) From 2d88b76c75d322838cd655bd6cd709181ea9fe6f Mon Sep 17 00:00:00 2001 From: Peter van Tol Date: Sat, 17 Oct 2026 11:13:41 +0200 Subject: [PATCH 09/10] refactor: bound qualification complexity without changing controls --- .../qualify_installed_http_successor.py | 57 +++++++----- .../qualify_installed_projectless_idle.py | 88 +++++++++++-------- 2 files changed, 90 insertions(+), 55 deletions(-) diff --git a/scripts/qualification/qualify_installed_http_successor.py b/scripts/qualification/qualify_installed_http_successor.py index 2f9a6a7a..b76e5348 100644 --- a/scripts/qualification/qualify_installed_http_successor.py +++ b/scripts/qualification/qualify_installed_http_successor.py @@ -1283,20 +1283,7 @@ def _phase(root: Path, scenario: str, phase: str, endpoint: str) -> None: if time.monotonic() >= deadline: raise RuntimeError("concurrent start barrier timed out") time.sleep(0.01) - if (root / "controlled-late-start.private").exists(): - original_preflight = runtime.preflight - def controlled_preflight(*args, **kwargs): - result = original_preflight(*args, **kwargs) - marker = root / ("race-start-b.preflight.private" if phase == "race-start-a" else "race-start-a.finished.private") - if phase == "race-start-b": - (root / "race-start-b.preflight.private").write_text("observed") - control_deadline = time.monotonic() + 20 - while not marker.exists(): - if time.monotonic() >= control_deadline: - raise RuntimeError("controlled late-start barrier timed out") - time.sleep(0.01) - return result - runtime.preflight = controlled_preflight + _install_late_preflight(runtime, root, phase) try: runtime.start(mission_id, _initial_truth()) except Exception as error: @@ -1306,8 +1293,7 @@ def controlled_preflight(*args, **kwargs): else: fixture._write(root / f"{phase}.race.private.json", {"result": "STARTED"}) finally: - if phase == "race-start-a": - (root / "race-start-a.finished.private").write_text("finished") + _mark_start_finished(root, phase) elif phase == "after-a-cut": def before_successor() -> bool: observed = runtime.states.get(mission_id) @@ -2529,6 +2515,39 @@ def _scenario(root: Path, scenario: str, wheel: Path, *, observer=None) -> dict: **({"recovery": recovery_summary} if recovery_summary is not None else {})} +def _install_late_preflight(runtime, root, phase): + if not (root / "controlled-late-start.private").exists(): + return + original_preflight = runtime.preflight + def controlled_preflight(*args, **kwargs): + result = original_preflight(*args, **kwargs) + marker = root / ("race-start-b.preflight.private" if phase == "race-start-a" else "race-start-a.finished.private") + if phase == "race-start-b": + (root / "race-start-b.preflight.private").write_text("observed") + deadline = time.monotonic() + 20 + while not marker.exists(): + if time.monotonic() >= deadline: + raise RuntimeError("controlled late-start barrier timed out") + time.sleep(0.01) + return result + runtime.preflight = controlled_preflight + + +def _mark_start_finished(root, phase): + if phase == "race-start-a" and (root / "controlled-late-start.private").exists(): + (root / "race-start-a.finished.private").write_text("finished") + + +def _validate_late_control(args, parser): + if args.late_start_control and (args.scenario != "concurrent-start" or args.phase is not None): + parser.error("late-start control requires only the concurrent-start parent case") + + +def _attach_single_flight(report, error, scenario): + if scenario == "concurrent-start" and hasattr(error, "single_flight_observation"): + report["failure"]["single_flight"] = error.single_flight_observation + + def _concurrent_accepted(outcomes, submissions, invocations): """One actual winner, one exact canonical refusal, and one original effect.""" expected = { @@ -2807,8 +2826,7 @@ def main() -> int: "preflight-stage", "preflight-first", "preflight-repeat")) parser.add_argument("--endpoint") args = parser.parse_args() - if args.late_start_control and (args.scenario != "concurrent-start" or args.phase is not None): - parser.error("late-start control requires only the concurrent-start parent case") + _validate_late_control(args, parser) if args.source_revision is not None and ( len(args.source_revision) != 40 or any(character not in "0123456789abcdef" for character in args.source_revision) ): @@ -3007,8 +3025,7 @@ def main() -> int: for frame in traceback.extract_tb(error.__traceback__)], "stage_trace": fixture._read( root / scenario / "stage-trace.public.json", [])}) - if scenario == "concurrent-start" and hasattr(error, "single_flight_observation"): - report["failure"]["single_flight"] = error.single_flight_observation + _attach_single_flight(report, error, scenario) fixture._write(root / "installed-http-successor.public.json", report) print(json.dumps(report, sort_keys=True)) return 1 diff --git a/scripts/qualification/qualify_installed_projectless_idle.py b/scripts/qualification/qualify_installed_projectless_idle.py index c6afe21d..3a6a0133 100644 --- a/scripts/qualification/qualify_installed_projectless_idle.py +++ b/scripts/qualification/qualify_installed_projectless_idle.py @@ -30,6 +30,57 @@ def child(root,port): app.serve_forever() +def _wait_readiness(process, port, wanted): + deadline=time.monotonic()+15;body=None + while time.monotonic() Date: Sat, 17 Oct 2026 12:07:20 +0200 Subject: [PATCH 10/10] fix(qualification): publish complete crash-boundary PID atomically --- .../qualify_installed_candidate_decisions.py | 12 +++- tests/test_candidate_boundary_publication.py | 71 +++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 tests/test_candidate_boundary_publication.py diff --git a/scripts/qualification/qualify_installed_candidate_decisions.py b/scripts/qualification/qualify_installed_candidate_decisions.py index f5f34fde..12a0c14e 100644 --- a/scripts/qualification/qualify_installed_candidate_decisions.py +++ b/scripts/qualification/qualify_installed_candidate_decisions.py @@ -23,6 +23,16 @@ def boundary_counts(root): decisions=db.execute('SELECT count(*) FROM governance_decisions').fetchone()[0] return intents,decisions,receipts +def _publish_boundary_pid(root): + # Publish only complete PID bytes; existence is the parent's crash signal. + pending = root / 'decision-boundary.pending.private' + pending.touch(mode=0o600, exist_ok=False) + try: + pending.write_text(str(os.getpid())) + os.replace(pending, root / 'decision-boundary.ready.private') + finally: + pending.unlink(missing_ok=True) + def phase(root,stage): cases=test_driver();q=cases.qual;original=q.utils.fixture.IDENTITY payload=json.loads((root/'decision-request.private.json').read_text());baseline=0 if payload['kind']=='BUSINESS' else 1 @@ -31,7 +41,7 @@ def identity(): intents,decisions,receipts=boundary_counts(root) wanted={'crash-before-effect':(baseline,baseline),'crash-between-stores':(baseline+1,baseline),'crash-after-effect':(baseline+1,baseline+1)}[stage] if intents==baseline+1 and (decisions,receipts)==wanted: - (root/'decision-boundary.ready.private').write_text(str(os.getpid()));time.sleep(20) + _publish_boundary_pid(root);time.sleep(20) return original with patch.object(q.utils.composition.MacOSGeneratedUIDIdentityAdapter,'resolve',side_effect=identity),ExitStack() as stack: server=q.ForgeServerRuntime(data_root=root/'runtime',credential_file=root/'admin.private',host='127.0.0.1',port=0,provider_id=q.utils.fixture.PROVIDER) diff --git a/tests/test_candidate_boundary_publication.py b/tests/test_candidate_boundary_publication.py new file mode 100644 index 00000000..1fd7b758 --- /dev/null +++ b/tests/test_candidate_boundary_publication.py @@ -0,0 +1,71 @@ +"""Deterministic regression for the actual TDE empty crash-boundary PID race.""" +from contextlib import contextmanager +from importlib.util import module_from_spec, spec_from_file_location +import os +from pathlib import Path +from tempfile import TemporaryDirectory +from threading import Event, Thread +import unittest +from unittest.mock import patch + + +def driver(): + source = Path(__file__).resolve().parents[1] + spec = spec_from_file_location('candidate_boundary_probe', source / 'scripts/qualification/qualify_installed_candidate_decisions.py') + module = module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +class CandidateBoundaryPublicationTests(unittest.TestCase): + def test_ready_path_is_not_visible_while_pid_write_is_incomplete(self): + module = driver() + opened, release = Event(), Event() + original = Path.open + failures = [] + with TemporaryDirectory() as tmp: + root = Path(tmp) + ready = root / 'decision-boundary.ready.private' + + @contextmanager + def delayed_open(path, mode='r', *args, **kwargs): + with original(path, mode, *args, **kwargs) as handle: + if path.parent == root and ('w' in mode or 'x' in mode): + opened.set() + if not release.wait(3): + raise AssertionError('test writer was not released') + yield handle + + def publish(): + try: + module._publish_boundary_pid(root) + except BaseException as error: + failures.append(error) + + with patch.object(Path, 'open', delayed_open): + worker = Thread(target=publish) + worker.start() + try: + self.assertTrue(opened.wait(3)) + self.assertFalse(ready.exists(), 'partial PID file is visible to the crash controller') + finally: + release.set() + worker.join(3) + self.assertFalse(worker.is_alive()) + self.assertEqual(failures, []) + self.assertEqual(ready.read_text(), str(os.getpid())) + self.assertEqual(ready.stat().st_mode & 0o777, 0o600) + self.assertEqual(list(root.iterdir()), [ready]) + + def test_failed_publication_does_not_advertise_a_boundary(self): + module = driver() + with TemporaryDirectory() as tmp: + root = Path(tmp) + with patch.object(module.os, 'replace', side_effect=OSError('synthetic publication failure')): + with self.assertRaises(OSError): + module._publish_boundary_pid(root) + self.assertEqual(list(root.iterdir()), []) + + +if __name__ == '__main__': + unittest.main()