Skip to content

feat(pull-migration): pull/work-stealing coordination Phases 0–3 (dark) + pilot (#1081)#1550

Merged
vybe merged 16 commits into
devfrom
feature/target-arch-pull-migration
Jul 14, 2026
Merged

feat(pull-migration): pull/work-stealing coordination Phases 0–3 (dark) + pilot (#1081)#1550
vybe merged 16 commits into
devfrom
feature/target-arch-pull-migration

Conversation

@obasilakis

@obasilakis obasilakis commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Pull / Work-Stealing Coordination — Phases 0–3 (dark) + proven pilot

Implements the local-buildable core of the pull/work-stealing dispatch migration (umbrella #1081, Epic #1045), per docs/planning/TARGET_ARCHITECTURE.md (v2 / Direction B). Everything ships behind PULL_MODE_PILOT_AGENTS (default empty ⇒ inert) — with the flag off, the push path is byte-for-byte unchanged.

One-line model

The backend owns one durable per-agent queue (schedule_executions: queued → claimed/running → terminal). Each agent's worker pool pulls the next task when it has a free worker, runs it, and POSTs the result back under a CAS guard. Nothing is pushed at a busy or dead agent.

What's in this PR

Phase Scope
0 Dark nullable claim_token / lease_expires_at / claimed_by_worker + redelivery_count on schedule_executions (dual-track: SQLite migrations.py + Alembic 0015/0016)
1 Dark pull endpoints — GET /api/internal/next-task (atomic claim + lease) + POST /api/internal/tasks/{id}/result (CAS); scoped-key dual-auth (no master secret in agents)
2 Agent worker pool (pull_worker.py) gated per-agent by PULL_MODE_PILOT_AGENTS; env injection at create/recreate
3 Lease-reaper + MAX_REDELIVERY (re-queue same execution_id, poison-park at cap) + capacity shadow meter + canary S-01 lease-exclusion

Phases 4 (sync edge adapter + fan-out join) and 5 (default-ON + delete legacy) are not in this PR — they gate on a ≥2-week zero-orphan soak (#856) and the side-effect gates.

Load-bearing invariants

  • Default OFF — empty allowlist ⇒ no worker, no lease, meter no-op.
  • Re-delivery preserves execution_id (effect_guard / feat: idempotency keys at all execution trigger boundaries (RELIABILITY-006) #525 dedup depend on it).
  • Leased rows owned exclusively by the reaperlease_expires_at IS NULL excludes them from 6 other sweeps + canary S-01.
  • No master secret in agent containers — pull seams use the agent's scoped MCP key.
  • Additive until Phase 5 — push path / slot ZSET / overflow LIST / dispatch-breaker-gate / canary S-01–S-03 untouched.

Fixes surfaced by testing (real-PG + concurrency)

  • C1 (critical): claim_next_queued double-claimed → double-ran rows under real-Postgres contention (uncorrelated InitPlan subquery + no outer status re-check). Fixed with FOR UPDATE SKIP LOCKED + outer status='queued' re-check — real-PG race 0/25 (was 25/25).
  • B1–B6: de-pilot didn't stop pulling; park/requeue nulled claim_token (late SUCCESS lost); silent poison on crash; in-flight terminal dropped on shutdown. Fixed. (B4 budget-doubling + slow-worker double-run deferred by design to Phase 5 / effect_guard.)
  • G1/G2: compose didn't forward PULL_MODE_PILOT_AGENTS; recreate dropped TRINITY_BACKEND_URL. Fixed.
  • PG1: over-length Alembic revision IDs — superseded on dev by bug: Alembic migration 0009 aborts backend boot on PostgreSQL — revision id (41 chars) exceeds alembic_version.version_num VARCHAR(32) #1420 (0008a_widen_alembic_version + env.py widening), inherited here; pull revisions renumbered 0015/0016.

Testing

  • 368 passed / 21 skipped across pull, canary, migrations, schema-parity, Alembic guards, capacity/backlog/slots.
  • Live pilot proven on real Postgres: migrations 0010 → 0016 applied cleanly; the pull worker pool authenticates (scoped key) + polls; a real task flowed queued → claim (lease + worker) → run → CAS result → success with ZCARD(slots)=0 throughout (pure-lease invariant).

Rollback

Flag-gated + additive by design, so rollback is cheap (full runbook: docs/planning/PULL_MIGRATION_ROLLBACK.md):

  • Tier 0 (seconds): empty PULL_MODE_PILOT_AGENTS + restart backend → de-piloted workers get 403 and idle (result-report path stays open so in-flight results land); recreate the agent to stop the worker process. Handles a misbehaving pilot.
  • Tier 1: for a push-fleet regression with the flag empty, redeploy the previous image — leave the nullable columns (expand/contract-safe, no DB step).
  • Tier 2: DB downgrade rarely/never needed.
  • Detection: operator-queue poison-park items, climbing redelivery_count, fleet failure rate. ⚠️ Canary SQL-tier checks are blind on Postgres until G3 (Canary invariant harness is blind on PostgreSQL — reads stale SQLite /data/trinity.db #1540).

Docs

  • docs/planning/PULL_MIGRATION_STATUS.md — status / handoff (consolidated).
  • docs/testing/PULL_MIGRATION_TESTING.md — tiered QA plan + findings + live-pilot record.
  • docs/planning/PULL_MIGRATION_ROLLBACK.md — rollback runbook.
  • docs/planning/MESSAGE_ENVELOPE_SCHEMA.md + ACTOR_MODEL_POSTCARD.md — wire contract + status/error taxonomy.

Umbrella: #1081 · Epic #1045

🤖 Generated with Claude Code

Fold the ephemeral session docs into two durable status docs and keep the
wire-contract specs separate:

- docs/planning/PULL_MIGRATION_STATUS.md  <- ORCHESTRATOR_SESSION_CONTEXT.md
  + PULL_MIGRATION_SESSION_HANDOFF_2026-07-07.md + PRD.json
- docs/testing/PULL_MIGRATION_TESTING.md  <- PULL_MIGRATION_TEST_PLAN.md
  + PULL_MIGRATION_RECONCILED_TESTING.md

MESSAGE_ENVELOPE_SCHEMA.md (#945) and ACTOR_MODEL_POSTCARD.md stay as
separate cross-linked reference docs. Removes root-level PRD.json /
ORCHESTRATOR_SESSION_CONTEXT.md clutter. Docs only.
…hase 0)

Dual-track (SQLite db/migrations.py + Alembic) nullable columns on
schedule_executions:
- claim_token, lease_expires_at, claimed_by_worker (Alembic 0015)
- redelivery_count, distinct from #678 retry_count (Alembic 0016)

DDL mirrored in db/schema.py + db/tables.py + db_models.py so fresh builds
stay correct (invariant #3). All columns nullable and unread until later
phases wire them, so this is a true no-op for the existing fleet.

Alembic revisions renumbered 0015/0016 during rebase (re-parented onto dev
head 0014_agent_schedules_webhook_auth). The original PG1 env.py version_num
widening is dropped — superseded by dev's #1420 (0008a_widen_alembic_version).
…r, capacity meter (#1081 Phase 1+3)

Dark backend pull path (no production caller; push path unchanged):

- GET /api/internal/next-task: atomic claim of the oldest queued row for an
  agent, stamps claim_token/lease_expires_at/claimed_by_worker, status->running.
- POST /api/internal/tasks/{id}/result: CAS-applies a terminal (status
  precondition + claim_token match); idempotent replay.
- Dual-auth on both seams: X-Internal-Secret OR the agent's own scoped MCP key
  (authorize_heartbeat) — no master secret in an agent container (#1159/#307).
- lease-reaper (services/lease_reaper_service.py + cleanup _sweep_expired_leases):
  under MAX_REDELIVERY re-queue the SAME execution_id (redelivery_count++), at
  cap FAIL + park to the operator queue. Re-delivery preserves execution_id so
  effect_guard/#525 keep deduping (#1402 invariant).
- lease_expires_at IS NULL exclusion on 6 non-reaper selectors so leased rows
  are owned exclusively by the reaper; park/requeue registered in the #1082
  status-guard.
- capacity shadow meter (count_active_leased_by_agent -> CapacityManager
  get_all_states/get_slot_state): read-only; admission stays on the ZSET.

Fixes C1 (found on real PG): claim_next_queued double-claimed -> double-RAN a
row up to N x under READ COMMITTED (uncorrelated InitPlan subquery + no outer
status re-check). Adds FOR UPDATE SKIP LOCKED + outer status='queued' re-check;
real-PG multi-process race 0/25 double-claims (was 25/25). Also keeps
claim_token on park/requeue so a late SUCCESS can CAS-overwrite (B2/B5) and
creates the operator alert before the park write (B3).

MAX_REDELIVERY=3 and PULL_MODE_PILOT_AGENTS (default empty) in config.py.
… Phase 2)

- agent_server/services/pull_worker.py (wired in agent_server/main.py): bounded
  pool (N = max_parallel_tasks) that short-polls next-task, runs the turn, POSTs
  the result with claim_token; decorrelated-jitter backoff mirroring #1083
  result_callback. Persists the completed terminal to
  ~/.trinity/pending-pull-results/<eid>.json before delivery, re-sends leftovers
  on startup, and drains on shutdown so an already-billed turn is never dropped
  (B6).
- services/agent_service/pull_mode.py: injects TRINITY_PULL_MODE /
  TRINITY_MAX_PARALLEL_TASKS ONLY for agents in the PULL_MODE_PILOT_AGENTS
  allowlist, at create (crud.py) + recreate (lifecycle.py). Default empty
  allowlist => no agent opts in => proven no-op.
- B1: recreate pops PULL_MODE_ENV_KEYS before re-applying so a de-piloted agent
  clears the baked flag; the claim seam's agent-key path is allowlist-gated.
- G2: recreate setdefaults TRINITY_BACKEND_URL so a legacy agent opted into pull
  keeps a backend URL (matches the #1098 TMPDIR idiom).

Worker auths with Bearer ${TRINITY_MCP_API_KEY}; no master secret injected.
Exclude leased rows (lease_expires_at IS NOT NULL) from the S-01 slot-row
bijection via an additive snapshot.running_lease_expires_at, so a pull pilot
does not false-fire in_sql_only. A genuine slot-row mismatch on a non-pull
row still fires. E-05/E-01 are the same class and remain open (see
docs/testing/PULL_MIGRATION_TESTING.md T3.6/T3.7 — apply before opt-in or
retire with the ZSET at Phase 5).
… G1)

The backend service uses an explicit environment: list (not env_file), so the
documented pilot opt-in (set PULL_MODE_PILOT_AGENTS in .env + restart) was a
no-op. Forward PULL_MODE_PILOT_AGENTS=${PULL_MODE_PILOT_AGENTS:-} so the flag
reaches the backend process from the tracked compose alone.
@obasilakis
obasilakis force-pushed the feature/target-arch-pull-migration branch from 469379d to bd046ea Compare July 9, 2026 10:28
Tiered rollback plan for the pull-coordination change:
- Tier 0: empty PULL_MODE_PILOT_AGENTS + restart (instant off-switch for a
  misbehaving pilot; result-report path stays open so in-flight results land).
- Tier 1: redeploy previous image for a push-fleet regression; leave the
  additive nullable columns (expand/contract-safe, no DB step).
- Tier 2: DB downgrade rarely/never needed.
Plus pre-deploy checklist, detection signals (incl. the G3 canary-on-PG blind
spot), scenario->response table, and the Phase-5 point-of-no-return note.
Linked from PULL_MIGRATION_STATUS.md.
…dark schema columns (#1081)

Review follow-ups (I1/I2):
- I1: add TestClaimConcurrencyC1 — a Postgres-only, multi-thread regression for
  the C1 double-claim fix. N workers race N queued rows through the REAL
  claim_next_queued; a correct claim is an exact N-way partition, so removing
  the FOR UPDATE SKIP LOCKED + outer status='queued' guards (all N would claim
  the head row) fails the bijection. Skips on SQLite / when TEST_POSTGRES_URL is
  unset. Replaces the torn-down scratch harness; verified passing on real PG.
  The prior suite only proved SEQUENTIAL no-double-claim, which passes with or
  without the fix.
- I2: document the 4 dark pull columns (claim_token / lease_expires_at /
  claimed_by_worker / redelivery_count) in architecture.md's schedule_executions
  schema — they ship to every instance, so the DDL block was stale.
…iew)

Durable bug class from the /review of #1550: an UPDATE ... WHERE id = (scalar
subquery) compiles to a once-evaluated InitPlan, so under Postgres READ
COMMITTED every concurrent updater re-applies to the same id unless the mutated
predicate is re-checked in the OUTER WHERE and/or FOR UPDATE SKIP LOCKED is
used. Also records why a sequential claim test cannot catch it.
…dark surfaces (#1081)

Address /validate-pr #1550 findings:
- W1 (config packaging, #1056 class): PULL_MODE_PILOT_AGENTS + MAX_REDELIVERY
  were read by the backend (config.py) but the .env levers didn't reach a prod
  deploy — prod compose launches standalone (no env_file merge). Wire both into
  docker-compose.prod.yml + docker-compose.yml backend.environment and document
  them in .env.example, so the pilot opt-in is actually settable on prod (still
  default-empty = fully dark).
- W2 (architecture doc): catalog the dark pull surfaces — the two internal
  claim/result seams on pull_router, the additive lease-reaper in the Cleanup
  Service, and the capacity shadow meter (metering-not-admission).
@vybe

vybe commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Held during the sequenced merge pass (validated via /validate-pr). This 45-file pull/work-stealing epic (#1081) touches capacity_manager, cleanup_service, schedules, canary, and adds pull_worker/lease_reaper/pull_coordination services — it warrants a dedicated /review + /cso --diff pass rather than a batch merge, even though the flags ship dark (default-OFF).

Two things need doing before it can land:

  1. Rebase onto dev — now CONFLICTING after fix(channels): count inbound client messages on the Sharing-tab roster (#1533) #1554 merged (shared architecture.md, database.py, learnings.md).
  2. Alembic re-chainfeat(mcp): make per-agent MCP connector OSS-core (trinity-enterprise#118 Part A) #1555 (merging now) adds 0015_enterprise_connectors off 0014_agent_schedules_webhook_auth. This PR's 0015_schedule_executions_pull_claim_lease also chains off 0014, so post-feat(mcp): make per-agent MCP connector OSS-core (trinity-enterprise#118 Part A) #1555 they're two heads and alembic upgrade head fails. Re-point 0015_schedule_executions_pull_claim_lease.down_revision to 0015_enterprise_connectors (and renumber it + 0016_schedule_executions_redelivery_count0016/0017). The pg-migrations check guards this. Also reconcile the SQLite db/migrations.py version list.

No changes pushed to this branch.

@github-actions

Copy link
Copy Markdown

⚠️ Nightly unit-suite check skipped — merge conflict against dev.

Resolve by running git merge dev locally and pushing the result. The next nightly run will re-test once the conflict is gone.

…-existence oracle (#1081)

CSO finding (LOW): POST /api/internal/tasks/{execution_id}/result returned 404
for a missing execution but 403 for an existing-but-not-owned one — a
cross-tenant existence oracle reachable by any valid agent-scoped MCP key,
against all executions, even with pull-mode OFF (the endpoint's auth is inline,
not allowlist-gated). Violated the self-uniform enumeration-safety invariant
(#186) and deviated from the #1083 callback (agents.py:1045) it claims to
mirror. Bounded to LOW by 128-bit token_urlsafe(16) execution_ids (not
enumerable), but it ships live.

Fold the missing-and-not-owned cases into a uniform 404. Adds a #186 regression
test asserting a not-owned and an unknown execution are indistinguishable (same
status + body).
#1081)

Point-in-time security audit of PR #1550's new attack surface (pull seams,
worker, reaper, config). 1 LOW finding (execution-existence enumeration oracle
on the result seam) — fixed in 4294488 — plus clean phases + the
scoped-key-over-master-secret improvement. Historical record under
docs/security-reports/ (out of the enterprise-docs-guard scope).
…nto 0015_enterprise_connectors (#1081)

Resolves the PR #1550 review blockers.

Conflicts (all additive-vs-additive, both sides kept):
- db/migrations.py — dev's enterprise_connectors_table (#118) + this branch's two
  pull migrations; MIGRATIONS list ordered to match the new Alembic chain.
- canary/snapshot.py — dev's E-04/G-04 queued_meta collection (#1077) alongside
  this branch's lease_expires_at collection (#1081 Phase 3). Both columns are
  PRAGMA-guarded independently.
- tests/test_canary_invariants.py — _add_execution helper takes both parameter
  sets (duration_ms/queued_at/backlog_metadata + lease_expires_at).
- learnings.md — both sides' entries retained.

Alembic re-chain (two heads after #1555 landed 0015_enterprise_connectors off
0014, which this branch also chained off):
- 0015_schedule_executions_pull_claim_lease -> 0016, down_revision now
  0015_enterprise_connectors.
- 0016_schedule_executions_redelivery_count -> 0017.
- Chain is linear again: 0014 -> 0015_enterprise_connectors -> 0016 -> 0017
  (single head, verified via ScriptDirectory.get_heads()).
- Rollback runbook downgrade target corrected: 0015_enterprise_connectors, NOT
  0014 — the latter would also drop dev's enterprise_connectors table.

SQLite track reconciled: enterprise_connectors_table + the two pull migrations
all present in MIGRATIONS, in Alembic order.
@obasilakis

Copy link
Copy Markdown
Contributor Author

@vybe both blockers addressed — pushed as a dev merge commit (4986a4c), no force-push.

1. Merged dev (the nightly bot asked for git merge dev, so merge rather than rebase). Four conflicts, all additive-vs-additive — both sides kept:

File Resolution
db/migrations.py dev's enterprise_connectors_table (#118) + this branch's two pull migrations; MIGRATIONS list ordered to match the new Alembic chain
canary/snapshot.py dev's E-04/G-04 queued_meta collection (#1077) alongside this branch's lease_expires_at collection. Both columns PRAGMA-guarded independently, so a minimal/older DDL still degrades fail-open on each
tests/test_canary_invariants.py _add_execution takes both parameter sets (duration_ms/queued_at/backlog_metadata + lease_expires_at)
docs/memory/learnings.md both sides' entries retained

architecture.md and database.py auto-merged — the conflict you saw there was from the pre-#1560/#1565 state.

2. Alembic re-chained. 0015_schedule_executions_pull_claim_lease0016 (down_revision now 0015_enterprise_connectors), 0016_schedule_executions_redelivery_count0017. Chain is linear again:

0014_agent_schedules_webhook_auth
  → 0015_enterprise_connectors        (dev, #1555)
    → 0016_schedule_executions_pull_claim_lease
      → 0017_schedule_executions_redelivery_count

ScriptDirectory.get_heads() → single head. SQLite track reconciled: enterprise_connectors_table + both pull migrations all in MIGRATIONS, in the same order.

One thing your comment surfaced beyond the re-chain: the rollback runbook's downgrade target was alembic downgrade 0014_agent_schedules_webhook_auth, which after the re-parent would also drop dev's enterprise_connectors table — unrelated to this feature. Corrected to 0015_enterprise_connectors and verified.

Verification (not just the guards — I reproduced the pg-migrations job locally against a real PG 16, seeded with the narrow VARCHAR(32) alembic_version to reproduce the #1420 pre-fix state):

  • alembic upgrade head → applies 0001 … 0017 cleanly; head = 0017_schedule_executions_redelivery_count; alembic_version widened to 255; enterprise_connectors present (proves no revision was skipped over); all four pull columns correct (claim_token/lease_expires_at/claimed_by_worker TEXT nullable, redelivery_count INTEGER default 0).
  • alembic downgrade 0015_enterprise_connectors → pull columns remaining: 0, enterprise_connectors preserved: 1 — i.e. the corrected runbook step does exactly what it now claims.
  • scripts/ci/check_alembic_parity.py origin/dev HEAD → PASS, both tracks updated.
  • pytest tests/unit3844 passed, 13 skipped; pull + canary suites (incl. test_canary_invariants.py) → 233 passed, 1 skipped.

Still yours to schedule: the dedicated /review + /cso --diff pass. Agreed it shouldn't ride a batch merge.

…nto 0018

Conflicts were all "both sides appended independent fields at the same spot"
(pull-coordination columns from #1081 vs. ephemeral-agent / voice-replies-v2 /
source-channel work from dev) — resolved as unions, keeping both:

  db/schema.py, db/tables.py, db_models.py, db/schedules.py,
  docs/memory/architecture.md   schedule_executions: claim/lease/redelivery
                                columns + ent#117 source_channel columns
  db/migrations.py              SQLite migration list: dev's entries, then ours
  services/cleanup_service.py   both counter sets + both in the total
  services/agent_service/crud.py  pull-mode env prep, then dev's ephemeral quota
                                reservation (which must stay adjacent to the
                                docker block so its rollback path still covers it)

Alembic: dev added 0016/0017/0018 while this branch had renumbered its own
revisions to 0016/0017, forking the chain (two revisions with
down_revision=0015_enterprise_connectors ⇒ "Multiple heads", `upgrade head`
would fail). Git does not flag this — both sides just add files. Re-chained the
pull revisions onto dev's head:

  0016_schedule_executions_pull_claim_lease -> 0019 (down_revision=0018_...)
  0017_schedule_executions_redelivery_count -> 0020 (down_revision=0019_...)

Chain is single-headed again (21 revisions, no forks, no dangling parents).

Also fixes a latent sys.modules leak the merge exposed: four pull tests popped
"utils" out of sys.modules to evict the tests/utils helper package, but
tests/unit/conftest.py already installs src/backend/utils as the canonical
"utils" via an importlib file loader for exactly that reason. Popping it left
"utils" unbound, and pytest's prepend import mode puts tests/ back at
sys.path[0] — so the next fresh `import utils` bound tests/utils, and every
later `from utils.url_validation import ...` in backend code died at collection
(15 collection errors once dev's new test modules landed in that window). The
tests now use the same idempotent sys.path bootstrap as their siblings.

Verification: full unit suite 3899 passed / 13 skipped, 0 collection errors,
in both fixed and randomized order. The one failure
(test_1474_read_boundary_z::test_schedules_summary_last_run_at_normalized) is
pre-existing and reproduces identically on clean dev and on the pre-merge
branch head.
…into pull-migration

dev advanced while the previous merge was in flight. Same union-shaped
conflicts as before — both sides appending independent fields:

  services/cleanup_service.py     CleanupReport: keep the #1081 lease-reaper
                                  counters alongside dev's #1581 volume-reclaim
                                  and #1142 operator-queue-retention counters —
                                  in the field list, the total, and to_dict().
  tests/unit/test_cleanup_inner_sweeps.py
                                  shared db-mock fixture: keep both stubs
                                  (find_expired_leases + prune_operator_queue_
                                  terminal_items), or whichever sweep is missing
                                  its stub blows up on a Mock return value.

Alembic chain unaffected (dev added no revisions): still single-headed at
0020_schedule_executions_redelivery_count, 21 revisions, no forks.

Verification: full unit suite 3951 passed / 13 skipped, 0 collection errors.
The single failure (test_1474_read_boundary_z::test_schedules_summary_last_run_
at_normalized) is pre-existing on dev and unrelated to this branch.
…nto 0019 (#1597)

dev's #1597 landed 0019_agent_sync_state_git_dir_bytes (also revising 0018),
colliding with this branch's 0019/0020. Re-chained: pull_claim_lease -> 0020
(down: 0019_agent_sync_state_git_dir_bytes), redelivery_count -> 0021. SQLite
MIGRATIONS list keeps both tracks (git_dir_bytes entry first, matching dev
apply order). Doc references updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@vybe vybe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validated via /validate-pr: dark by construction (PULL_MODE_PILOT_AGENTS empty ⇒ inert; push path untouched — one claim path, no fork), dual-auth pull seams keep the master internal secret out of agent containers with the pilot-allowlist consumer backstop + uniform-404 enumeration safety (Inv #8/#186), claim-token CAS terminal writes preserve #1082 status-as-projection, lease reaper disjoint via lease_expires_at IS NOT NULL. Dual-track migrations + compose/env.example wiring in-PR; CSO diff audit committed; extensive named #1081 tests. Merged dev in and re-chained Alembic onto 0019_agent_sync_state_git_dir_bytes (now 0020/0021, pg-migrations green); 90 overlap-sensitive unit tests pass locally on the merged state; head pytest green ×3 seeds (base seed-12345 leg was a cancelled hang measuring dev, not this PR — dev CI itself fully green). ✅

@vybe
vybe merged commit ce8f6a5 into dev Jul 14, 2026
20 of 22 checks passed
obasilakis pushed a commit that referenced this pull request Jul 17, 2026
…t, derived request ids, cap semantics (#1402)

The MAX_REDELIVERY cap + poison-park mechanism shipped in Phase 3 (#1550);
this lands the remaining #1402 deliverable: the authored contract agents
receive.

- Platform prompt (PLATFORM_INSTRUCTIONS → Operator Communication): rewrite
  around fire-and-park / never block-and-wait (park → end the turn → process
  responded items in a later turn), ask-before-irreversible-actions guidance,
  execution-id-derived request ids (approval-{execution_id}-{slug} — global-PK
  collision safety + re-delivery dedup), expires_at + resume-instructions
  guidance for agents with no next turn. Section stays MCP-tool-name-free so
  the Codex transform can't fork it.
- _mode_guidance task mode: explicit park carve-out so "execute to completion,
  don't ask questions" no longer contradicts the gate on the exact autonomous
  path it targets.
- Synced the dead-but-present reference copy (config/trinity-meta-prompt/
  prompt.md, injection removed in #136) and added the agent-guide async-comms
  section (incl. honor-system framing).
- Docs: requirements/scheduling.md §10.13 (raw-attempts cap semantics + still-
  blocking list for pull default-on), TARGET_ARCHITECTURE.md stale claims
  fixed ("all unbuilt today" → shipped split), operating-room.md (async
  contract, poison-park items, removed-#136 prompt-integration correction),
  learnings.md (prompt-delivery-path pitfall).
- Tests: tests/unit/test_1402_prompt_contract.py — sentinel phrases across
  every runtime build, old block-inviting wording gone, section byte-identity
  across runtimes, carve-out, meta-prompt/guide sync (17 tests).

Residual work tracked: #1629 (pull-path prompt delivery + re-delivery banner),
create caps).

Fixes #1402

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
obasilakis added a commit that referenced this pull request Jul 17, 2026
…ived request ids (#1402) (#1635)

* feat(operator-queue): async human-gate contract — fire-and-park prompt, derived request ids, cap semantics (#1402)

The MAX_REDELIVERY cap + poison-park mechanism shipped in Phase 3 (#1550);
this lands the remaining #1402 deliverable: the authored contract agents
receive.

- Platform prompt (PLATFORM_INSTRUCTIONS → Operator Communication): rewrite
  around fire-and-park / never block-and-wait (park → end the turn → process
  responded items in a later turn), ask-before-irreversible-actions guidance,
  execution-id-derived request ids (approval-{execution_id}-{slug} — global-PK
  collision safety + re-delivery dedup), expires_at + resume-instructions
  guidance for agents with no next turn. Section stays MCP-tool-name-free so
  the Codex transform can't fork it.
- _mode_guidance task mode: explicit park carve-out so "execute to completion,
  don't ask questions" no longer contradicts the gate on the exact autonomous
  path it targets.
- Synced the dead-but-present reference copy (config/trinity-meta-prompt/
  prompt.md, injection removed in #136) and added the agent-guide async-comms
  section (incl. honor-system framing).
- Docs: requirements/scheduling.md §10.13 (raw-attempts cap semantics + still-
  blocking list for pull default-on), TARGET_ARCHITECTURE.md stale claims
  fixed ("all unbuilt today" → shipped split), operating-room.md (async
  contract, poison-park items, removed-#136 prompt-integration correction),
  learnings.md (prompt-delivery-path pitfall).
- Tests: tests/unit/test_1402_prompt_contract.py — sentinel phrases across
  every runtime build, old block-inviting wording gone, section byte-identity
  across runtimes, carve-out, meta-prompt/guide sync (17 tests).

Residual work tracked: #1629 (pull-path prompt delivery + re-delivery banner),
create caps).

Fixes #1402

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(1402): #1629 shipped — correct the stale pull-path prompt-delivery claims

The branch predates #1633 by ~1 minute (merged to dev 14:00:26Z; this PR
opened 14:01:39Z), so three docs assert a code state that is false on the
merge target:

- requirements/scheduling.md — #1629 listed under "Still blocking pull
  default-on" ("pull-claimed turns currently receive NO platform
  instructions at all")
- TARGET_ARCHITECTURE.md — "receive no platform instructions today ... still
  blocking default-on", and #1629 in the residual list
- feature-flows/operating-room.md — "Known gap (#1629): ... bypass
  platform-prompt composition entirely"

On dev, pull_coordination_service.py composes the platform prompt on the
claim path (fail-open) and injects the re-delivery banner. The still-blocking
list gates the pull default-on decision, so a resolved blocker sitting in it
costs a future reader real work.

#1629 stays referenced (status-in-dev — open until the release cut), now
described as shipped-pending-release rather than unbuilt. learnings.md is
left as-is: it records why #1629 was filed, which remains accurate history.

---------

Co-authored-by: Eugene Vyborov <eugene@beingluminous.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: obasilakis <vasileios.georgopoulos@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants