fix(heartbeat): hint deferred prompt upgrades through budgeted turn-start hooks - #4440
Conversation
Update-time reconciliation can only report a prompt migration it cannot write while the Codex App is running; the pending request lived in that one command's stdout. Record it per lane under the runtime root, with the same reviewed prompt-only request update-time already builds, so the obligation survives the report that discovered it. - share automation_update_request between the plan/reconcile paths instead of rebuilding the same App request inline - resolve only this host home's records, so one runtime root fronting several Codex homes keeps its other pending adoptions - drop a record once its reviewed body is installed, without re-classifying any lane Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
The heartbeat contract has to describe the automation the host actually runs. A recorded pending adoption is projected as scheduler_hint.app_automation.prompt_adoption with the reviewed prompt-only automation_update request, its no-spend policy, and both prompt digests, so the turn applies it once and reads the automation back without spending quota. The projection reuses the existing payload obligation channel rather than adding a scheduler-hint parameter, and a satisfied record stops projecting itself once the exact body is installed. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
The agent-facing CLI output differential measures the thin heartbeat prompt markdown against a 32-character hot-path allowance. Spelling the new obligation as `prompt_adoption=adopt(no-spend); ` grew those rows by 33 characters in all three thin variants (small, multi_agent, crowded), which fails `examples/control_plane/cli-output-budget-regression-smoke.py` and the kernel static checks job. Keep the clause and the no-spend marker, but drop the `prompt_` prefix inside the thin variant so the obligation costs 27 characters and leaves headroom. The full `prompt_adoption` field name stays visible in the compact and application rule variants and in the `scheduler_hint` payload. Validation: heartbeat-prompt-smoke.py, cli-output-budget-regression-smoke.py and cli-output-base-head-differential-smoke.py (base=102 candidate=102) pass; test_prompt_adoption_projection.py, test_automation_prompt_upgrade.py and test_cli_output_budget.py report 70 passed. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Hot-path prompt budget fix (head
|
| Check | Result |
|---|---|
examples/control_plane/cli-output-base-head-differential-smoke.py |
ok — base=102 candidate=102 candidate_only=0 review_required=0 |
examples/control_plane/cli-output-budget-regression-smoke.py |
ok |
examples/control_plane/heartbeat-prompt-smoke.py |
ok |
pytest tests/control_plane/test_prompt_adoption_projection.py tests/control_plane/test_automation_prompt_upgrade.py tests/control_plane/test_cli_output_budget.py -q |
70 passed |
Failures or skips: none in the set above. The earlier, unrelated examples/install-local-smoke.py failure reported for the previous head is pre-existing on origin/main and is not touched by this change. Host-side readback of the projected app_automation.prompt_adoption on a real Codex App wake remains a manual hold for the operator.
…pt-obligation Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
…pt-obligation Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
…ng turn-start hook Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Change
When
loopx update applycannot migrate an eligible automation prompt, retain a compact private receipt and inject a repair hint only while that same automation still runs the old body.required_readschannel and points to a fresh, automation-scopedautomation-prompts plan.No new prompt template, permanent heartbeat instruction, skill clause, scheduler action or standalone capability is introduced. Detection remains update-time; arbitrary external edits are reviewed through the existing plan command.
Hook-owned prompt budget
The active hint declares
prompt_budget_bytes=1536. The existing typed hook contract admits at most 2048 bytes per read. Only an emitted hook read carries that allowance into the Agent/CLI command projection and adds it to the Turn envelope's 8192-byte budget. Inactive hooks contribute zero; existing unbudgeted reads retain their 360-character projection. This budget grants no execution or quota authority.Validation
npm run typecheck:control-planepassed.git diff --checkpassed.quota should-run/ plan CLI, current/pending parity, other-host isolation, stale/custom/deleted/ambiguous entries and long command projection are covered.Entry points: Codex App heartbeat quota and shared managed-Turn decision. No new configuration or frontend control is needed: the existing Agent/CLI required-read channels carry the hint; other host decisions retain parity.
Qualification and merge hold
db82c25987380dd8bb713a72e5128bba3b0b456f52f605d556243ac62e90f3be, 12 files; head7dd4332b8, immutable baselinec979cf11c.cqr_db82c25987380dd8bb71records the remaining failed installer validation and is not a passing merge qualification.examples/install-local-smoke.py:367fails itsmaterialized_skill_idsassertion. The same assertion fails on an isolated cleanc979cf11cbaseline and on the final head. There are no test skips.PR remains for review; merge is held on the pre-existing installer validation failure.