Target-line bug, not introduced by the replay: Worker._tenant_dirs
only receives project_id, yet the script_skipped_modified log line
used task.get("project_id"), raising NameError whenever seeding
reported a tenant-modified script (the refreshed sibling branch was
already fixed to project_id with its own regression test; this test
only covered the refreshed branch, so the full suite stayed green).
Fix mirrors the sibling (project_id) plus a regression test for the
skipped branch. Ruff F821 in worker.py is thereby cleared.
Target keeps the 6-mixin split, so the source line's 239/223/16 and
its mixin-homed 17-method list do not apply here. Recomputed by AST
on this line: handler accounting 244 total / 150 in server.py /
94 moved, no duplicates (243/149 + _update_goal_task); longfunc
still 17 methods with the same names, 16 homed in server.py and
_full_auto_execute in handler_fullauto.py, plus module-level
migrate_tasks_table in server.py (114 lines). No method split or
dropped; both tests' docstrings state the re-pin explicitly.
(cherry picked from commit 073950043ed65039e19be8a4b6d725a44a662879)
Reconcile-note: this datefix was missing from the solidify line (aa30d40's test_arch_converge.py had no _current_month_day and still failed in November, while 10023fb/6841f28 contained it); added here as the separately-labeled fix for that replay omission, per the reconcile brief.
Server writes goal + monotonic goal_version + task_goal_history in one
transaction (CAS on version, approve_merge only, new-semantic goal tasks
only, terminal/merged 409, same-goal noop). Worker mirror thread (30s)
and breakpoint-resume claim hook write the update as a signal file next
to host-state.json; host run_goal_loop applies it at round boundaries
(top of round and before the declaration check, so a declaration made
for the old goal in a turn during which the goal changed is voided),
with an explicit old->new notice, same thread/worktree, rounds/usage/
budget/failed counters untouched. handler method accounting is a
contract update: 239 total / 223 mixins / 16 in server.py.
(cherry picked from commit 6841f287219d2b36cfbb8803642344b84dae4377)
Reconcile-port: handler_lifecycle.py contents redirected — _update_goal_task method + _goal_update_reject/_goal_signal_status pure functions + goal_live_update import into cloud/server.py (target keeps 6-mixin split); _task_to_dict goal fields into cloud/handler_support.py; migrate columns into cloud/server.py migrate_tasks_table; test patch target handler_lifecycle→server; test_handler_split_conformance.py kept at target version, to be re-pinned for the unified line in a final commit.
- LiveEvidenceReader protocol: get_checks(repo, ref) /
get_branch_protection(repo, branch), results carry status
plus raw evidence; production code has no HTTP call, no
token read, no real GitHub API call (AST-asserted).
- verify_live_evidence: no reader / no repo-ref / reader
failure / mismatch all verified=False; comparison shared
with verify_gate_evidence via _compare_claimed_vs_live.
- live_gate_decision: verified=False -> allowed=False,
http_status=409, status=blocked; verified=True -> 200.
- Endpoints _merge_task/_release_task NOT wired yet (no
production reader exists; wiring None would block all
merges/releases); real live verification still pending
B6 real App install and B1 user-side items.
(cherry picked from commit 7e8bfdee1f22c28329602314f3e166cde34eb6cf)
- cloud/scorecard_diff.py: audit_scope (changed files + claimed_fixed,
unchanged/baseline-out files out of package), ScorecardGainLedger
(memory) + SqliteScorecardGainLedger (SQLite only, PG_DDL text-only),
three tables code/production/product kept separately, average
reference-only; check_stagnation: two consecutive code gains <0.5
(test_default_unapproved) escalate, no auto pushback; rubric_version
change starts a new sequence.
- cloud/tests/test_scorecard_mech_diff.py: 24 tests, all passing.
- No change to audit_loop_driver.py semantics, #238 auto_apply,
#247 correction-pass semantics, or v1.1 contract.
(cherry picked from commit 57d44becaf559a074c995249e95bd36924dae13f)
(cherry picked from commit b7ac9d7d6af842a182964b0aa0524708e7cdc923)
Reconcile-note: resolution kept target's finalized wording verbatim, so this commit is empty by content (docstring-only commit; both sides agreed: migration side, no revert).
(cherry picked from commit 1db02545f74c96b3b92be4fc32954659cec1f814)
Reconcile-conflict: A14b E402 imports referencing cloud.handler_core (does not exist here; core methods live in server.py) — kept HEAD imports with incoming's noqa: E402 markers, dropped the unused core_mod import (verified unused elsewhere in both files).
(cherry picked from commit 4411186681584bf55e065c654fe909a3320d4a22)
Reconcile-conflict: test_skill_transplant_prep artifact count — kept HEAD's finalized 0 refs (2026-11-02 user sign-off deleting §4's 6 references, already in target) with incoming's l→line rename; incoming's 6-ref assertion is pre-finalization and must not overwrite.
(cherry picked from commit 908df30d1a3cf328ea05344f0660af9b77bf24a1)
Reconcile-port: handler_support.py kept at HEAD (189 lines; A13 domain comments describe source's 1616-line handler_support layout, which does not exist here — functions live in server.py). test_longfunc_inventory.py kept as-is for now; it pins source architecture and will be re-pinned for the unified line in a final commit (recorded).
- peer_messages.row_get gains default=None (was None-only); the
three old variants agree on all real row types (None / dict /
sqlite3.Row): auto_memory's old default was already None, and
lifecycle's old None special-case and dict .get give identical
results on those types, so no call-site behavior changes and no
call site passes a non-None default.
- auto_memory and lifecycle delete their private _row_get copies
and import peer_messages.row_get as _row_get (precedent: server,
worker, handler_project, handler_support already do this);
peer_messages imports no cloud modules, so no import cycle.
lifecycle's old broad-Exception catch differs only for pathological
__getitem__ inputs, which are not DB rows and are out of contract;
this is documented on row_get, not left as a second story.
- Scope note: other modules' own row_get copies (approvals,
automations, marker_tools, todos, wait_ops) are out of this item's
stated scope and are untouched.
- Also drops auto_memory's unused 'import os' (pre-existing F401),
so touched files are ruff E,F clean.
- Tests: cloud/tests/test_row_get_unified.py locks the identity
(both aliases ARE row_get), the real-row-type matrix, the
None-default fallback, and snapshot_to_dict via the unified path.
(cherry picked from commit 1644a0b837bfefb13cdc3c93d87fc1b246026607)
- model_breakdown inferred params as a 1-tuple from the first
branch, so params + (month,) was tuple[Any] vs tuple[Any, str].
Annotate params as bare tuple (tuple[Any, ...]) before branching.
- Annotation only: the () initializer is never used (if/elif/else
always overwrites it), runtime semantics unchanged.
- mypy cloud/: 0 errors in 94 files (was 1 error); ruff clean;
cost tests 39 pass.
(cherry picked from commit a9fd0692361e8169554413b725c81135be2c5525)
- New production caller cloud/worker_sweep.py (python -m
cloud.worker_sweep): AuthStore.authenticate + CODEX_GLOBAL_ADMINS
global-admin check (same fail-closed semantics as
handler_admin._is_global_admin) before any reap call; denied
authenticated non-admins get an admin_worker_sweep_denied audit
row; authorized runs reuse reap_stale_workers (classify, re-verify,
pre-kill audit fail-closed, per-pid SIGKILL only, post-kill
verification) plus an admin_worker_sweep summary audit; --dry-run
lists classifications only.
- No new HTTP route, no container enumeration, no name/prefix
matching, no workers-row deletion; workers.py docstring only notes
the new caller.
- Tests: cloud/tests/test_worker_sweep_admin.py, 6 cases (bad key,
non-admin, unconfigured admin list fail-closed, authorized full
chain, dry-run, CLI main authorized/refused).
(cherry picked from commit c7d217549c5ccedf61dcc924b8998fffeddc76c6)
process_audit_verdict now calls validate_signer_separation
before any state save or ledger write (previously the function
had no production caller on this path: it only ran inside
collect_failed_checks via decide_pushback, which itself has no
production caller). Signer is bound to the authenticated
caller -- a body signer differing from the caller is rejected
-- and executor/coordinator_approver/qa_tester must be
declared and distinct from the caller; missing field,
self-audit, or forged signer raises ValueError, mapped by
_loop_run to HTTP 400 with no side effects. No new route.
Honest limits are in the helper docstring: declared-identity
enforcement only (task rows store no authoritative executor /
coordinator / QA identity; task executor is a backend, not a
person), and audit-fix reaudit verdicts are out of scope
(the fix poster is not necessarily the re-auditor, so binding
signer to the fix poster would be a mis-binding).
(cherry picked from commit 56dce5165f4d08f38fe1730b9eea3b78f90cb97d)
Reconcile-port: handler_lifecycle.py docstring hunk redirected into cloud/server.py audit-verdict handler (target keeps 6-mixin split; enforcement itself is in audit_loop_wiring.py and applied cleanly).
Pre-fix any first-attempt audit failure raised NameError at
auth.py:424 (sqlite3 never imported), aborting the 5-attempt
retry loop on attempt 1 and masking the original error. The
424-line coverage mystery is also explained: the only full-suite
hit is test_child_model.test_coordinator_inherits_child_defaults
via worker best-effort _audit swallowing an OperationalError
(database is locked); 422-423/426-427 stay uncovered because
rollback succeeds and NameError aborts before either raise.
Bubble audit (see report): no merge/release gate swallows the
NameError and proceeds, so this stays a downgrade, not a
production blocker.
(cherry picked from commit 039c6adbac3b120b5b9a1dcbafeff6a91407ce70)
Postgres audit_ledger append-only guard gains exactly one
execution entry: cloud/ledger_pg_guard.apply_pg_guard, runnable
as 'python3 -m cloud.ledger_pg_guard' (explicit ops command,
not a migration script). It executes PG_GUARD_SQL verbatim from
the constant -- no second copy of the SQL anywhere -- refuses
non-PgConnection targets, does not commit itself (caller/CLI
commits), and refuses with exit 2 on a non-postgres backend so
a no-PG environment can never claim hardening. ensure_schema
still skips PG triggers; POSTGRES_SCHEMA still builds only the
table. Tests lock all of this with a recording fake connection
(no PG execution is faked), a source scan asserting only
ledger.py and ledger_pg_guard.py reference the constant, and
CLI dry-run/refusal cases. Real-PG syntax and UPDATE/DELETE
blocking verification is explicitly left to B5, not claimed here.
(cherry picked from commit b1f6c9158d628186965a9e57576ff8c9500e3f73)
Server POST /tasks/{id}/merge no longer has record/enforce/off:
hard_mode_from_env and HARD_MODES deleted (not re-defaulted),
handler always evaluates the hard gate, env CLOUD_MERGE_GATE_MODE
and body merge_gate_mode are ignored server-side. The record
'no-evidence passes' and 'unprotected+confirm passes with
merge_gate_risk' server paths are gone with the dead risk audit;
no production caller justified keeping them (only production
caller of the non-hard evaluator was the merge handler itself;
audit_loop_wiring already used the hard gate). cloud/merge_gate
pure functions keep their #209 semantics but are documented as
non-server: they are no longer wired to any endpoint.
Server-level record/enforce/off tests rewritten to the new
behavior (renamed, not deleted silently); pure-function tests
unchanged.
(cherry picked from commit 08e75edbd6d04701965c5db951fa054cfbb75bb0)
Reconcile-port: handler_lifecycle.py hunks redirected into cloud/server.py _merge_task (target keeps 6-mixin split; mixin file does not exist here); handler_support.py kept at HEAD (its A1 hunk is a docstring of _validate_hard_gate_body, ported to server.py copy); test mock paths cloud.handler_lifecycle.* rewritten to cloud.server.*.
- restore _audit_row in cloud/automations.py as a thin wrapper over
cloud.auth.audit_on_conn (legacy row + ledger entry pair,
user_id system, best-effort self-commit preserved). The stack's
gap-4 option A deleted the direct writer; main #275 resident.py
imports _audit_row, so the bare rebase broke server import.
No direct audit_log INSERT is reintroduced, so the #250
no-bypass scan stays green.
- conformance accounting 238/144 -> 243/149: main #275 added 5
resident methods that legitimately stay in server.py; moved
count stays 94, no duplicates.
- directional: resident x3, audit chain, conformance, automations
x3 suites, 51 tests OK
- whitelist expansion (tr + exit builtin) confirmed, comment only
- B4 viewport wording: temp banner removed, wording untouched,
change-list table stays in draft, not merged into body
- B3-tail (a)/(b): no content change (bullet still absent), recorded
as decided; v2 record showed it unselected, no side picked here
- section 4: 6 templates/artifacts/ refs deleted per signed verdict;
tripwire test updated 6 -> 0 to pin the new inventory
- CHANGELOG pointer line kept, no marker present
- workers audit landing migration confirmed, comment only
- verify-script gate evidence confirmed, gate hard untouched
- 2 temp stances NOT touched: actual-only quota, evidence binding
not enforced / no anti-restamp
- behavior code unchanged; directional skill tests 39/39 OK
- cloud/evidence_binding.py: bind/validate/nonce single-use store;
release endpoint consumes nonce on first validated submission,
replay -> 409 evidence_replayed, stale/future -> 409
evidence_stale, partial -> 400, absent -> old path + label.
Binding blocks exact replay and stale evidence, NOT restamping
(unsigned evidence cannot prove content freshness).
- cloud/quota.py docstring: actual-only is the v2 integration
position (already converged in v1 base via fef09ae, NOT in
main); original PR semantics (#86 all-rows vs #90 actual-only)
still pending coordinator confirmation at merge time.
- cloud/ledger_onboarding.py: DDL checklist referencing
PG_DDL/PG_MARKER_DDL constants, read-only verify_ledger_ready
and ledger_setup_report; default stays OFF, PG DDL stays an
operator action (never claimed as executed).
- cloud/ledger_outbox.py + worker hook: ledger write failures
go to a JSONL outbox in addition to the log and can be
replayed; task outcome still unaffected (rule 7 kept),
audit fail-closed untouched -- asymmetry documented, not
silently changed.
- cloud/gate_verification.py: read-only verifier over an
injected reader (match/mismatch/skipped); live wiring in
merge/release is NOT possible on the current contract (no
repo/ref in body or task row, no guaranteed trusted token),
proven in the module header; no fake verification claimed.
- cloud/tests/test_v2_evidence.py: 18 new tests, all passing.
(cherry picked from commit bd85e33cd5e846fa6ee5d7e2440182dbd9c758b0)
- db: translate INSERT OR IGNORE ... SELECT to ON CONFLICT DO NOTHING;
register task_audit_loop_state (task_id) in _OR_REPLACE_PK (direct port).
- server: _backfill_default_quotas uses SAVEPOINT containment, no longer
commits the caller's transaction (direct port; callers are init_db only).
- worker: NOT ported — integration _coord_child_rows has no column-fallback
retry loop, so the InFailedSqlTransaction cascade site does not exist here.
- tests: rewritten for the integration base (no cloud.audit_loop /
_coord_audit_loop_merge here); real-PG cases skip without DSN/driver.
(cherry picked from commit 79e6843610fcd275af874e7b4afc57af7ffa579e)