D1-06: Public self-contained operator path for Scarcity Router-backed task execution (#44) #45
No reviewers
Labels
No labels
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Creatidy/creatidy-kernel!45
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "issue-44-selfcontained-operator"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Linked issue
Creatidy/creatidy-kernel#44 — D1-06: Public self-contained operator path for Scarcity Router-backed task execution.
Summary
Makes the public Kernel package self-contained for the bounded Scarcity Router-backed task operator path, without any
creatidy-onpremdependency and without configuring a local Scarcity Router checkout path.adapters/source_cache.py): normal operation no longer requiresCREATIDY_KERNEL_SOURCE_REPOSITORY. The controller acquires its own read-only cache from the TaskSpec canonical repository (${XDG_CACHE_HOME:-~/.cache}/creatidy-kernel/source/<org>/<repo>), re-verifies the exact canonical origin before every reuse, refreshes with a bounded fail-closed fetch, and never searches sibling directories or workspace layouts.--reporemains an advanced override with the existing exact verification. Acquisition is read-only with respect to the remote; the disposable candidate workspace stays a separate controller-owned tree; exact-base freezing is unchanged.adapters/codex_discovery.py):CREATIDY_KERNEL_CODEX_BIN/VERSIONare optional. Deterministic single-candidate resolution (override, else firstcodexon the suppliedPATH), a--versionprobe in the closed operational environment, version-shape validation shared with the runtime parser, and closed failure categories (not_found,probe_failed,unsupported_version). A unusable resolved installation is never silently substituted; no thread or turn is ever started during discovery/doctor/preflight.${XDG_STATE_HOME:-~/.local/state}/creatidy-kernel/task;--data-dir/env overrides unchanged; SQLite storage-safety checks unchanged.adapters/operator_profile.py): bounded literal dotenv parsing, JSON-profile parsing, validation that reports key names only, and an optional generic SOPS adapter using a user-supplied profile plus the user's own SOPS key environment (--profile PATH --sops; explicit profile values override the ambient environment for that invocation). Not a secrets manager; no committed secrets, no Creatidy-specific recipients, hosts, or paths.creatidy-kernel config template | config validate,doctor, plustask preflight/run/status/exportwith defaults.doctorrenders the same readiness gate with safe diagnostics and fixed hints.category. Router failures distinguish endpoint unreachable / HTTP rejection / invalid response / no eligible selection / selection incompatible with the controller binding (real loopback-HTTP tests). Source failures distinguish acquisition / fetch / remote mismatch / checkout suitability / dirty override / exact-base problems.Preserved (verified by the existing suite)
TaskSpec authority; exact-base freezing and durable recovery; controller-owned candidate creation; closed Codex child environment; inference-free preflight with no Forge writes; no automatic merge/deploy; trusted-development acknowledgment; #143/#166 durable identities; the Scarcity Router boundary through the
ResourceAllocatorport (no policy embedding, no routing framework).Validation
make check: PASS (uv lock, ruff format/check, basedpyright strict 0 errors, lint-imports KEPT, 966 tests passed, secret scan clean,git diff --check).make package-check: PASS (wheel/sdist rebuild, isolated install, CLI replay/export smoke).make audit: not run (no dependency or tooling changes).Acceptance evidence
tests/test_source_cache.pyandtests/test_selfcontained_operator.pyprove, with real Git fixtures and native-shaped fakes, that a zero-inferencedoctor -> task preflightflow works with no source/state/codex configuration across two unrelated filesystem layouts, that a canonical sibling checkout is never adopted or touched, and that acquisition output is independent of checkout placement.Independent full-PR review of the frozen head
c2944f0da538e60fb67f091bd70e66eea212e141(basedevelop@fa81734ed10bfbdd6e7a75b138649a89a9724511), performed by a fresh read-only reviewer session dispatched on GLM-5.3 per the owner-mandated model override for this delivery. The reviewer session is distinct from the implementation session and posted nothing itself; this submission persists its verdict.platform_identity_limitation: the configured reviewer identity is the same account that authored this PR, so Forgejo refuses a formal self-approval ("approve your own pull is not allowed"); the substantive verdict below is independent of that platform state, andforgejo_review_statefor this review is COMMENT withplatform_approval_recorded = false.PR Review: D1-06: Public self-contained operator path for Scarcity Router-backed task execution (#44) (#45)
Repository: Creatidy/creatidy-kernel
Branch: issue-44-selfcontained-operator -> develop
Frozen head:
c2944f0da5Linked issue: Creatidy/creatidy-kernel#44 (D1-06 — Public self-contained operator path for Scarcity Router-backed task execution)
Frozen-input verification (run this review): Forgejo MCP
get_pull_request_by_index(45)returned headissue-44-selfcontained-operator@c2944f0da538e60fb67f091bd70e66eea212e141, basedevelop@fa81734ed10bfbdd6e7a75b138649a89a9724511(merge base identical), state open, not merged — matches the frozen inputs exactly. Local checkout:git rev-parse HEAD=c2944f0da538e60fb67f091bd70e66eea212e141, clean tree on the head branch. Issue #44 fetched viaget_issue_by_index(44); 12 changed files confirmed vialist_pull_request_filesandgit diff --stat fa81734e..c2944f0(2037 insertions / 79 deletions).Summary
The PR makes the public package's bounded-task operator path self-contained. It adds (1) a controller-owned read-only source cache acquired from the TaskSpec canonical remote (
src/creatidy_kernel/adapters/source_cache.py, new), (2) deterministic single-candidate Codex discovery with a--version-only probe (adapters/codex_discovery.py, new), (3) generic dotenv/JSON operator profiles with an optional generic SOPS decrypt adapter (adapters/operator_profile.py, new), (4) safe closed diagnostic categories on preflight blockers plus Router failure categories (adapters/task_execution.py,adapters/scarcity_router.py), and (5) a public CLI surfaceconfig template|validate,doctor,task preflight/run/status/exportwith user-local XDG defaults (adapters/cli.py). No core or ports files change; README documents the new surface. All changes sit inadaptersplus tests and README.Intent / Acceptance Evidence
CREATIDY_KERNEL_SOURCE_REPOSITORY; controller-owned read-only cache from canonical remote; exact origin verification; read-only remote; no sibling/home/workspace search;--repostays an advanced override; no generic discovery frameworktask_execution.py:1837-1853(resolve_source: override → configured field → canonical cache);task_execution.py:2008-2017(preflight acquires when unset);source_cache.py:59-70(URL-shape-validated cache key, no filesystem search anywhere in the module),source_cache.py:139-152(exact origin re-verified),source_cache.py:168-184(fresh clone withcredential.helper=,http.followRedirects=false,--template=),source_cache.py:276-284(bounded fail-closedfetch --prune originrefresh),source_cache.py:286-288(foreign/corrupt entry replaced, never adopted); teststests/test_source_cache.py:53-98(two layouts, no placement leakage; canonical sibling never adopted or touched),:100-145(reuse fetches, failed fetch fails closed)CODEX_BIN/CODEX_VERSIONoptional when an unambiguous supported Codex is on PATH; deterministic resolution;--versionprobe; shared inference-free validation; no silent substitution; no thread/turncodex_discovery.py:95-113(override else first on PATH, single candidate);codex_discovery.py:63-83(probe only--version, closed failure mapping, output never echoed);codex_discovery.py:25+task_execution.py:1563(one shared version pattern);task_execution.py:1936-1955(environment_with_discovered_codex); teststests/test_codex_discovery.py:42-64(deterministic first-hit, override wins),test_selfcontained_operator.py:165-186(preflight ready with no manual Codex fields)task_execution.py:1806-1811(default_state_directoryhonoring absoluteXDG_STATE_HOME);task_execution.py:1814-1834(task_paths: CLI → field → default; source may be None); unchanged state gates attask_execution.py:2018-2052;cli.py:309-316(status/export default); testtest_selfcontained_operator.py:445-454.sops.yamldependency, env config still supported, generic SOPS adapter, user-local profile paths, secrets never printed/serializedoperator_profile.py:39-53(bounded literal dotenv),:56-71(JSON profile),:74-105(generic SOPS: user-supplied profile, user's ownSOPS_*env only),:108-127(symlink/size-refusing loader),:130-141(field-name-only diagnostics),:144-149(XDG config default); teststest_operator_profile.py:93-131(SOPS passthrough verified, failures safe),:147-157(template generic, host/onprem absent)cli.py:230-243(config,doctorsubcommands),cli.py:116-162(_config),cli.py:164-202(_doctor),cli.py:309-339(status/export/preflight/run); no new Make targets; README "Public Operator Surface" (README.md:281-323); teststest_selfcontained_operator.py:345-442scarcity_router.py:38-46(RouterFailureCategory),:385-394(HTTP/encoding/deadline classified),:413-424(request/no-eligible/incompatible),:463-472(OSError → endpoint unreachable; raise outside handler);source_cache.py:34-40(source categories);task_execution.py:2053-2089(checkout/remote/dirty/base subcategories on explicit sources);cli.py:43-105(fixed hints); teststest_selfcontained_operator.py:239-319(real loopback HTTP for five router categories, secret-absence asserted),:188-225(discovery categories)ResourceAllocator; no policy embedding, no Router-as-Runtime, no product copy, no routing frameworkmake checkranlint-imports: "Adapters depend inward; core and ports never depend on adapters KEPT"doctor -> task preflightwithout creatidy-onprem and without a configured checkout pathtest_selfcontained_operator.py:364-415: CLIdoctorthentask preflight --jsonboth READY with Codex from PATH, XDG state default, source acquired by the controller,inference_performed/forge_writes_performedfalse;:345-361:doctorwith an empty environment fails closed with categories and hintstest_source_cache.py:53-79(two unrelated remote/state layouts, varying cache roots, same logical content, no placement strings in.git/config) andtest_selfcontained_operator.py:117-142(preflight parametrized over two unrelated layouts, same acquired cache evidence)test_operator_profile.py:153); the onlyforgejo.creatidy.comoccurrences are the pre-existing frozen TaskSpec canonical URLs already on basefa81734e(task_execution.py:490,:535) — TaskSpec authority data this PR does not touch_preflight_base/_resolve_base(task_execution.py:1856-1890),run_task(:1196+),prepare_workspacecall (:1296-1298) unchanged; child env stays the closed key set (:1463-1469); preflight payload still reportsinference_performed/forge_writes_performed/execution_authorizedfalse (:1789-1793); run still requires--approve --trusted-development(cli.py, unchanged lines in diff context);TASKSregistry unchanged (:600); 966 existing+new tests passArchitecture / Information Flow
All new modules live in
adaptersand import only adapters (source_cache.py:23-24,operator_profile.py:24,codex_discovery.pyimports nothing internal); no core/ports file changed, and the import-linter layers contract was verified KEPT bymake checkin this session. Authority stays where it was: TaskSpec still solely owns repository identity/base (resolve_sourceattask_execution.py:1837-1853reads onlytask.repository_url; infrastructure defaults never touch TaskSpec, pertask_paths's docstring:1821-1827). Information flow is one-directional: environment/profile → typed config → components; the cache namespace is controller-owned under${XDG_CACHE_HOME:-~/.cache}/creatidy-kernel/source(source_cache.py:51-56), and every reuse re-verifies the exact canonical origin before use (:253-259). Diagnostic flow carries closed vocabularies only:PreflightBlocker.categoryis regex-validated (task_execution.py:1753-1755) and Router categories are a fixed StrEnum (scarcity_router.py:38-46). Git acquisition runs in a freshly constructed environment (GIT_CONFIG_NOSYSTEM,GIT_CONFIG_GLOBAL=/dev/null,GIT_TERMINAL_PROMPT=0, no ambientGIT_*passthrough —source_cache.py:123-136), with a test proving ambienturl.*.insteadOfrewriting cannot redirect it (test_source_cache.py:203-219);run_git_boundedis shell-free, byte-bounded and process-group-killed (forgejo_transport.py:181-211).Blocking Issues
None. Fail-closed behavior holds on every path traced: discovery failure becomes a
codex_not_readyblocker with a closed category and never a substitution; acquisition failure becomes asource_not_readyblocker; a failed cache refresh refuses readiness rather than degrading (source_cache.py:276-284); explicit--reposources keep the full exact-origin/clean/base verification (task_execution.py:2055-2089).Non-blocking Suggestions
source_cache_key(source_cache.py:59-70) keys only on the URL path, so two forges hosting the same<org>/<repo>share one cache slot. Safety is intact (exact origin re-verified before every use; mismatch replaces the entry), but alternating tasks on different hosts would discard and re-clone each time.ConfigurationErrorhandler (task_execution.py:1980-1993), when the user supplied both Codex fields (discovery skipped) and another field is also invalid/missing, the Codex field names fall out of the diagnostics. Fail-closed is preserved; only the reported names are lossy.config validateignores the top-level--profile—_config(cli.py:116-162) uses only--config-profile/--config-sops, socreatidy-kernel --profile X config validatesilently validates the ambient environment instead ofX. Either honor it or reject the combination.profile_template()(operator_profile.py:152-179) writes the operator's currentHOMEandPATHinto the generated file. Not a secret leak, but pure placeholders would be cleaner._discard(target)thenstaging.rename(target)can race between concurrent invocations on the same machine; worst case is a redundant clone or a transientunsuitable_cacherefusal.evidence["source"]["cache_root"]is recomputed fromdefault_cache_root(enriched)rather than taken from the acquisition itself; identical in production.not_found— an explicitly configured but relative/non-executableCREATIDY_KERNEL_CODEX_BINis classifiednot_found(codex_discovery.py:98-105).Questions for the Author
--profilealso apply toconfig validate(see suggestion 3), or is the two-flag split intentional enough to document in README?Security / Privacy Notes
ConfigurationErrorcarries field names only;ProfileErrormessages are fixed; the Codex probe never echoes binary output; Router failures never echo response bodies and the exception is raised outside the handler; tests assert synthetic secrets absent from payloads.clone/fetch/status/config --get/remote set-url(local metadata) are issued;--versionis the only probe; no thread or turn is started in discovery/doctor/preflight..sops.yamlreferences exist in the new public code (grep-verified); SOPS is a generic adapter over the user's own key environment.Test / Documentation Gaps
docs/(grep-verified).make auditnot run — consistent, since the diff touches no dependency or tooling file.Checks run in this review (all as local untrusted checks; nothing pushed, no working-tree modification, no installs): focused new/affected tests → 112 passed;
make check→ PASS (966 tests, ruff, basedpyright, lint-imports KEPT, secret scan clean);make package-check→ PASS. Not verifiable from this public checkout: the reference inspection of privateInfrastructure/creatidy-onprem— confirmed instead that the public product contains no runtime dependency on or constants from it.Follow-Up Candidates
Overall Recommendation
APPROVE
The frozen HEAD implements every required-architecture section of issue #44 with verifiable evidence, preserves the issue's entire "Preserve" list, keeps all changes inside
adapterswith the layers contract verified KEPT, and passes both repository gates in this session (966 tests; package-check). All findings are non-blocking diagnostics/UX/efficiency refinements. No live #166 execution, merge or deployment is included, per the issue's constraints.