Skip to content

feat(quota): seal should-run projection envelope - #6679

Open
Duang777 wants to merge 5 commits into
mainfrom
codex/quota-should-run-envelope
Open

Duang777 wants to merge 5 commits into
mainfrom
codex/quota-should-run-envelope

Conversation

@Duang777

Copy link
Copy Markdown
Collaborator

Goal And Delivered Outcome

  • Outcome basis / optional anchor: TypeScript control-plane migration RFC, projection-envelope rollout.
  • Goal/source and gap: quota should-run inherited status data but did not emit its own canonical freshness, completeness, source, and Goal-coverage envelope.
  • Observable before → after, with the validation row that proves it: Before, five quota cases failed with KeyError: projection_envelope. After, every active, paused or stopped, health-blocked, and unknown-Goal result emits loopx_projection_envelope_v0. The focused regression suite and the source and packaged CLI rows below prove the result.
  • Issue/task and intended base: RFC slice against main. No separate issue.

Author Declaration

  • Written by: OpenAI Codex agent.

Implemented against

  • Specification and revision: docs/architecture/rfcs/typescript-control-plane-migration-v0.md and docs/reference/contracts/projection-envelope-contract.md at base da7d0b9979.
  • Criteria:
Criterion (spec clause) Disposition Symbol / path Test or command
Every quota result carries a Goal-scoped envelope and inherits status evidence implemented build_quota_should_run tests/test_projection_envelope.py
Record only live sources that quota invokes implemented _tracked_read_callback, _record_app_scheduler_state_source test_quota_should_run_records_live_workspace_inbox_and_scheduler_reads
Keep freshness, completeness, and alert decisions in the TypeScript owner implemented projection.envelope.seal npm run typecheck:control-plane
Render envelope alerts before quota conclusions implemented render_quota_should_run_markdown test_quota_should_run_alerts_when_the_status_envelope_is_missing
Qualify the required interface growth without weakening later growth checks implemented quota interface budget and one-time CLI migration allowance hot-path and CLI differential smokes
  • Self-check before submission: Reviewed the full diff, the public and private boundary, every return path, budget evidence, and the final remote head. The change does not alter quota policy, authority, persistence, scheduler decisions, configuration, or frontend behavior.

Scope And Continuation

  • Completed scope and remaining work: Complete within the quota should-run rollout slice. The RFC still lists review-packet and Decision Context packets as later read-model adoptions.
  • Slice boundary / successor: The quota read model is independently testable and reversible. The existing RFC owns later adoption. This PR does not create a parallel follow-up.

Validation

  • Tested revision: 0a1cbfde9b977df2b17a8d0dc5693ab0a51f9de5
  • Run state: finished
  • Input classes: synthetic, public_fixture
Check kind Result Public-safe evidence / limitation
regression_parity passed Before implementation, five focused cases failed because projection_envelope was absent. After implementation and the final rebase, the related suite passed 228 tests.
regression_parity passed The CLI differential test first rejected four quota migration combinations, then two JSON compact-budget cases. The final eight migration combinations and the real base/head CLI matrix passed.
real_entrypoint passed A subprocess test ran python -m loopx.cli ... quota should-run from the source checkout and read back projection=quota_should_run.
real_entrypoint passed A wheel built from the tested head, installed into a fresh environment, and the packaged loopx quota should-run read back the Goal-scoped envelope.
static passed Ruff passed. The repository Mypy command passed its configured 17 files. The TypeScript control-plane typecheck passed. The semantic diff advisory found no supported new vocabulary carriers.
regression_parity passed The hot-path fixture measured 15,419 to 18,636 JSON characters, 378 to 513 nested keys, and 52 to 53 top-level keys. The new limits retain the full typed envelope.
integration passed loopx canary premerge --from-git-diff passed all 19 selected checks, including the public and private boundary and both interface-budget smokes.
  • Coverage and gaps: The checks cover all quota return paths, missing and stale upstream evidence, cadence failures, invoked live readers, Markdown ordering, source CLI output, installed-wheel output, and base/head interface growth. A nonstandard file-targeted Mypy experiment followed unrelated transitive imports and hit the repository's full-tree baseline. The repository command passed. The first package attempt also found stale local generated frontend state after the rebase. A clean isolated rebuild produced no tracked diff, and the wheel validation then passed. No PostgreSQL run was required because this change does not touch an authority store, persistence, or routing.

See validation disclosure guidance.

Frontend / Visual Evidence

  • UI impact: none
  • Before: N/A
  • After: N/A
  • States and viewports shown: N/A
  • Source data: none
  • Attention review: N/A. The existing CLI JSON and Markdown read model changes, but no visual UI changes.
  • Craft review: N/A

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Refactoring (no functional changes)
  • Documentation update
  • Test update

LoopX Area

  • Control plane (goals, todos, quota, scheduler, registry, runtime)
  • Benchmark boundary (adapters, runners, verifiers, scoring, evidence)
  • Capability or extension (providers, adapters, skills)
  • Public docs or presentation surface (README, protocols, dashboard)
  • Build, packaging, installer, or CI
  • Host or runtime integration

Technical Direction

  • Direction / acceptance reference, when applicable: Core control-plane hardening. TypeScript migration RFC projection-envelope rollout.

Shared-authority RFC fixture impact

  • Production-scale fixture schema: Not applicable. This read-model slice uses public synthetic Goal and source fixtures and does not claim authority promotion.
  • Semantic dimensions changed, or reviewed no-impact rationale: Adds quota freshness, completeness, direct-source status, upstream status inheritance, replay provenance, and Goal coverage. TypeScript remains the only owner of sealing semantics.
  • Provider conformance arms run: Not applicable. No provider contract changed.
  • Read-only legacy/file/PostgreSQL three-arm rehearsal (required for promotion, runtime-routing, or compatibility-projection changes): Not applicable. This change does not alter promotion, authority storage, runtime routing, or a compatibility projection.

Boundary Checklist

  • Neither the diff nor this PR body/comments/attachments disclose private state, credentials, raw traces or verifier output, internal links, or local machine paths (including .loopx/, .codex/goals/, and live ACTIVE_GOAL_STATE.md).
  • I did not duplicate maintainer-owned benchmark work unless a maintainer split out a public issue for it.
  • I kept the change scoped to the linked issue/task.
  • I completed the visual evidence section for UI changes, or marked UI impact none.
  • Every commit includes a DCO Signed-off-by trailer (git commit -s).

Signed-off-by: duang777 <duangjl007@gmail.com>

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewer: model_agent; model=gpt-6.1-sol; provider=OpenAI; runtime_reported; reasoning_effort=max

完整评审 6679@0a1cbfde9b977df2b17a8d0dc5693ab0a51f9de5,实际合并基线 da7d0b9979d2e7a2651cdc95230de70549278bfb。结论 REQUEST_CHANGES:有一个已通过真实读取路径复现的 P2。

动机

运行 quota should-run、需要判断当前结果是否可信的自动化 Agent 与本地操作者。

此前 quota 的决定没有自己的来源与覆盖说明,调用者无法直接区分当前、陈旧或不完整的读数;本次增加统一说明,目的是让调用者先看来源告警再决定下一步。

正常来源、状态继承、覆盖与渲染已有可执行覆盖;但独立真实 CLI 和 wheel 均证明损坏的调度状态仍被标成 fresh,整体 alert 为 false,因此核心可信读数尚未成立。

不改变算力准入、任务排序、调度策略或写权限,不完成 review-packet / Decision Context 的后续接入,不证明实际宿主安装、模型采用或持续运行收益。

quota 来源读数需要修复下面的 P2;review-packet 与 Decision Context 仍按既有 RFC 顺序推进,不能将本次接入称为完整迁移。

改动思路

沿用现有 Python quota 投影及唯一 TypeScript envelope owner 是合适的有界接入;来源 IO 的真实结果必须由现有读取 owner 返回,不能在 Python 根据参数存在重新推断成功。

当前 PR 只交付 quota 的真实来源、继承、覆盖及告警;要求修复真实调度读取事实并补负例,不要求先迁移整个 quota 或完成后续投影。

生产入口仍是 quota should-run,先取得 status,再按原有 quota / interaction / scheduler owner 生成决定,最后把直接读取事实与 status 的所有上游来源交给 projection.envelope.seal。Python 不判断陈旧阈值、覆盖完整性和告警组合,既有 TypeScript owner 决定这些语义;Markdown 复用统一告警渲染器。没有新持久化状态、开关或设置动作,也不需要用户重复授权来读取原有响应。这里是既有读模型的元数据接入,前端配置器没有新增可操作能力;没有把 CLI 配置描述当成新 UI 交付。

最强的反对理由是每次 quota 都增加载荷和维护成本,却可能仍然隐藏坏来源。因此关键验收是“真实失败能否被看见”,不能只看 schema、测试数或 seal 的输出形状。当前框架选择可以保留,缺口在读取事实的生产者;采用另一次 Python 文件探测或第二套 freshness 规则会进一步复制知识。

同一读取状态 基线 当前头与 wheel
两个调度键都不存在 原决定,未声明 quota 自身新鲜度 允许作为健康空读,符合声明
两个调度键都是损坏 JSON 原决定,无 quota envelope 仍声称 fresh,整体无告警,违反来源契约
两个调度路径是目录 原决定,无 quota envelope IO 读取失败仍声称 fresh,无告警
清除隔离坏数据后重新读取 原决定 恢复健康空读,原有决定与指令保持

此表来自实际 CLI、真实 TypeScript 文件读取与正常 wheel,不是流程示意或模型采用证明。

具体改动

独立规范在读 diff 前固定为 docs/reference/contracts/projection-envelope-contract.md,spec_revision: da7d0b9979d2e7a2651cdc95230de70549278bfb;同时对照相同基线的 docs/architecture/rfcs/typescript-control-plane-migration-v0.md §2.6。规范的当前 rollout 编辑不能反过来充当自己实现的验收依据。

  • 2.6 Projection envelope is a kernel read contract:implemented。quota 增加自己的 envelope,继承上游来源,保持 TypeScript 唯一判断 owner;paused、health、unknown 等返回也接入。
  • Field semantics:not_met。不可读来源必须告警,但新 scheduler 来源仅据参数存在推断成功,真实错误没有进入来源事实。
  • Consumer rule:not_met。渲染顺序本身正确,但调度来源出错时 envelope 告警为 false,调用者没有告警可披露,不能据此声称当前来源健康。
  • Cache and replay:implemented。复用原 TS seal 与上游 envelope,保留旧 observation、重算 freshness;缓存与陈旧来源测试通过。后续 review-packet / Decision Context 接入仍保留在既有 RFC 边界。

关键代码讲解

  • _attach_quota_should_run_envelope:Assemble source facts and requested Goal coverage; call existing TS seal exactly once. No own envelope -> inherited status and direct source envelope。
  • _record_app_scheduler_state_source:Records App scheduler source after real payload assembly. Infers read from parameters; currently falsefresh on actual read failure。
  • _projection_envelope_migration:Qualify one-time none -> v0 migration for canonical status/quota surfaces including variants. Status-only row prefix -> canonical surface id includes quota。
  • render_quota_should_run_markdown:Print envelope notice before quota decision. No quota notice -> common renderer。

其他差异也完整检查:双语 RFC 仅更新 quota rollout 及剩余入口;projection 文档描述实际来源;测试覆盖上游继承、未知 Goal、缺失 envelope、paused/health、cadence 失败、缓存与渲染,以及一次性输出迁移的反例。源码共 10 文件、+665/-59,主要增量是本地来源适配和 360 行聚焦测试,没有引入新框架或第二决策权威。

预算增加有同负载证据,不能因为旧上限而删去消费者需要的来源说明。独立 hot-path 对照是 quota JSON 15,419→18,636 字符、378→513 个嵌套键、52→53 个顶层键,新上限 20,500 / 525 / 54;原 heartbeat/status 形状没有改变。共享 differential 只为 canonical status / quota_should_run 的 none→v0 提供一次性余量,包括对应模式;同 v0 继续增长、其他 surface、逆向或未知版本不获豁免。实际完整 base/head 96/96 行通过,18 条 quota 迁移提示保留给审查者,没有新增行被隐藏。

对主干的风险

[P2] 调度状态读失败不能被标成 fresh

位置:loopx/control_plane/quota/should_run.py:208-212。有效 App context、runtime 和 Agent 并不能证明来源被成功读取。真实 _build_quota_should_run_payload 调用 scheduler loader;既有 state_store.ts::loadSchedulerState 将非 ENOENT / JSON 解析错误吞成 null,随后新 helper 仅检查两个参数是否非空,写入 read_status=read 和当前时间。seal 忠实处理这些错误的输入事实,于是输出 status=fresh、unreadable_count=0、alert=false。

我在一次性 runtime 中,通过 scheduler_state_path 找到当前键与 Codex 兼容键,分别放入损坏 JSON 和目录;独立物理读取分别得到 JSONDecodeError / IsADirectoryError。真实 API、生产 quota should-run --goal-id goal-a --agent-id reader-a --runtime-profile codex_app_heartbeat 和正常构建安装的 wheel 都复现上述错误健康标签,CLI 均退出 0。API 的 eligible 决定仍为 run;CLI 的已有 operator-gate 指令也保持原样。这里新增的错误是“失败来源被认证为新鲜”,没有声称这个 PR 新增了原有空状态 fallback 或授权绕过。

从实际 scheduler.state.load / load_app_automation_scheduler_state 读取边界带回成功、缺失与不可读事实,保留合法缺失为空的语义;将解析或 IO 失败映射为 unreadable 并由既有 TS seal 产生告警,不要仅由 runtime_root 与 agent_id 是否存在生成 read/fresh。

在隔离 runtime 内分别令当前与 Codex 兼容键的 scheduler_state_path 为不存在、有效状态、损坏 JSON、目录或读取失败;通过 quota should-run 的生产 CLI / 正常 wheel 验证损坏会告警、合法缺失不误报、修复后恢复,并重跑原 178 项测试与 CLI differential。

语义与 CI 对齐

本次复用既有 loopx_projection_envelope_v0 与 read/missing/unreadable/not_read 词汇,source id 是局部事实名;没有新共享生命周期或授权语义。开发期语义 advisory 没发现支持语法内的新载体,完整 semantic-vocabulary check 也通过,但这不能证明来源事实正确,当前 P2 直接违反既有 Field semantics / Consumer rule。回归应覆盖真实 TypeScript 读取错误,而不只用已归一化的正向 mock 替代读取结果。

独立验证:相关 pytest 基线 163、当前 178 项通过;native standard premerge 为 5 个直接检查及 19 个选择检查,failed=0、skip=0、manual hold=0,含真实 CLI 输出、quota 路由、scheduler、维护性与全部 10 文件 public-boundary 扫描。TS typecheck、mypy 17 文件、选定路径 Ruff、完整语义与 DCO/diff 均通过。初次 wheel 因复用工作区的旧 Chat 构建产物被正常校验拒绝,随后运行正常 build:chat 并重建 wheel,独立 site-packages 路径再次复现 P2;没有放松构建校验。未查询或等待远程 CI。

我的整体评价

整体方案与已接受的下一步一致,保留现有 TS owner、局部 Python facts adapter 和有证据的一次性预算调整是合理的。未来适配退出仍归原投影迁移;当前有界整理应把实际读事实从现有 IO owner 传回来,避免参数推断或重复探测,不要求无关的全量 TypeScript 重写。

long_horizon: preserved:四个真实对照场景中,除明确新增的 envelope、隔离路径拼写及生成时间,旧决定、完整指令和解压后的宿主 follow-up 事实逐字段相同;96 个 CLI 场景与原生路由验证没有发现调度或续行变化。这不证明长期收益。user_experience: regression:原先未知的新鲜度现在在坏来源上被错误标为健康,正是本次能力要消除的风险,因此当前头不能批准。

结论是 REQUEST_CHANGES,限于上述已复现的来源真实性缺口。修复后用同一真实 CLI / wheel 的缺失、坏数据与恢复对照重审新头;不以绿测试替代该观察,也不把这条评审视为合并、安装、宿主采用或后续迁移完成的资格。

English verdict: REQUEST_CHANGES - 0a1cbfd: actual corrupt/unreadable scheduler state is labeled fresh with no envelope alert; reproduced through the real source CLI and installed wheel despite 178 passing targeted tests, 96-row differential and 19 green native canaries. Preserve actual read outcomes at the existing IO boundary and test missing/error/recovery.

Comment thread loopx/control_plane/quota/should_run.py Outdated
if isinstance(identity, Mapping)
else ""
)
read = bool(status_payload.get("runtime_root") and agent_id)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] 调度状态读失败不能被标成 fresh。从实际 scheduler.state.load / load_app_automation_scheduler_state 读取边界带回成功、缺失与不可读事实,保留合法缺失为空的语义;将解析或 IO 失败映射为 unreadable 并由既有 TS seal 产生告警,不要仅由 runtime_root 与 agent_id 是否存在生成 read/fresh。 独立观察:真实 API、生产 CLI 与正常安装 wheel 均输出 app_scheduler_state.read_status=read、status=fresh、unreadable_count=0、envelope.alert=false;读取失败被误当成健康空状态,调用者看不到应该先披露的告警。 验证要求:在隔离 runtime 内分别令当前与 Codex 兼容键的 scheduler_state_path 为不存在、有效状态、损坏 JSON、目录或读取失败;通过 quota should-run 的生产 CLI / 正常 wheel 验证损坏会告警、合法缺失不误报、修复后恢复,并重跑原 178 项测试与 CLI differential。

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in a74b460d9, with regression coverage in 7f6c8c724 and 9ef61099a.

The TypeScript scheduler state store now reports the actual read result. Missing state is a successful empty read. Malformed JSON, directory reads, invalid state, and other I/O failures report unreadable. Python observes both the canonical and Codex compatibility-key reads; it no longer infers success from runtime_root and agent_id.

Validation on Node 22.22.3 / SQLite 3.51.3:

  • scheduler state store: 16/16 passed, including malformed canonical and legacy JSON plus a directory path
  • scheduler/projection Python suites: 59 passed
  • quota and CLI differential suites: 171 passed
  • exact-head premerge: 19/19 selected checks passed
  • built and installed wheel: packaged CLI returned fresh for missing state, unreadable with alert for corrupt state, then fresh after recovery
  • production CLI regression also covers directory-path I/O failure and recovery

Please re-review 6679@9ef61099af9ee83772020afb052e4d180feff6c3.

@mergify

mergify Bot commented Oct 16, 2026

Copy link
Copy Markdown

This pull request has merge conflicts with main and cannot be merged
until they are resolved. Please rebase or merge the base branch, @Duang777.

Choose the remote for the base repository, not an out-of-date fork.
For a fork clone, first inspect git remote -v; upstream must point
to https://github.com/loopx-project/loopx.git. If it is absent, add it
with git remote add upstream https://github.com/loopx-project/loopx.git.
Then run:

git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEAD

For a same-repository clone whose origin points to
https://github.com/loopx-project/loopx.git, use origin instead of
upstream for fetch/rebase. If you prefer merging the base, use
git merge <base-remote>/main and push normally.

Keep the DCO Signed-off-by trailer on every commit when you rebase.
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Oct 16, 2026
Signed-off-by: duang777 <duangjl007@gmail.com>

# Conflicts:
#	docs/architecture/rfcs/typescript-control-plane-migration-v0.zh-CN.md
Signed-off-by: duang777 <duangjl007@gmail.com>
Signed-off-by: duang777 <duangjl007@gmail.com>
@mergify mergify Bot removed the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Oct 17, 2026
Signed-off-by: duang777 <duangjl007@gmail.com>

This branch has not been deployed

No deployments
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