feat(projection): kernel-owned projection envelope for status, global-summary and global-gates - #5085
Open
huangruiteng wants to merge 1 commit into
Open
huangruiteng wants to merge 1 commit into
huangruiteng wants to merge 1 commit into
Conversation
…bal views Add loopx_projection_envelope_v0, sealed by the TypeScript kernel through projection.envelope.seal. Python adapters pass compact read facts only; TS decides freshness, alerts, and completeness. - status / --goal-id: per-source last_read_at and coverage relative to the requested scope; cached copies keep observed_at and restamp served_at - global-summary / global-gates: goal_quota source, upstream status envelope, and outside_current_registry omissions - Markdown renders a red projection line when stale, unreadable, missing, or incomplete - RFC: TypeScript control-plane migration section 2.6, baseline row, and correctness rule; reference contract and status data contract Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
LoopX projections (
status,global-summary,global-gates) are what operators and agents act on, but today a projection cannot say how old it is, which sources it actually read, or whether it covers the scope it claims. A cached status looks as current as a live one, an unreadable quota file looks like "no quota", andglobal-summaryrun against a project-scoped registry quietly reports one project's goals as if they were the whole machine.This PR makes that metadata a kernel-level read contract, owned by the TypeScript control plane, as part of the TS migration rather than as another Python-side helper.
What changes
Kernel contract:
loopx_projection_envelope_v0loopx/control_plane/projection_envelope.ts, registered as runtime methodprojection.envelope.seal. It is the single semantic owner of freshness, alerting and completeness.read_status/last_read_at/required/ counts, plus requested-scope coverage. It never computes freshness or alert state itself. The Python side is a thin facts adapter,loopx/control_plane/projection_envelope_facts.py. It is named so that it does not register as an independently maintained py/ts twin.observed_at,served_at,age_seconds,served_from_cache;last_read_at,read_status(read,missing,unreadable,not_read),required, a staleness window (default 300s),source_updated_at(informational only);coverage, relative to the requested scope:expected_count,included_count,omitted[]with a reason, count and bounded refs,shown_count/available_count,truncated;upstream[]and inherit upstream source rows (markedvia) and upstream completeness;fresh,complete,alert,alert_reasons⊂ {stale_sources,unreadable_sources,missing_required_sources,incomplete_coverage},alert_source_ids.shown < available) never alerts on its own.Rollout in this PR
status/status --goal-idregistry,global_registry(optional),goal_run_indexes,goal_state_contract,runtime_projection_routes(optional)registry,goal, oractivation.<state>global-summarygoal_quota+ upstreamstatusenvelopeglobal(expected = global registry goal count)global-gatesglobalobserved_atand is re-served through the kernel, which restampsserved_atand re-evaluates staleness. An entry with no envelope, or a tampered one, becomes a cache miss (missing_projection_envelope/invalid_projection_envelope) and is never served blind.current_registry_excluded_goal_countand boundedcurrent_registry_excluded_goal_ids. The global views use them to reportoutside_current_registryomissions.projection:line with age, fresh-source ratio and coverage. When the envelope alerts, it is prefixed with 🔴 and followed by an explicit alert line telling the reader to state the problem before treating the projection as current or whole.Example:
global-summaryrun with a project-scoped registry on a machine with 48 registered goals now reports:RFC: TypeScript control-plane migration
projection.envelope.seal, the adapter exit condition (Python adapters stop computing any envelope semantics; when a projection moves to TS they pass the same facts in-process), the rollout order, and the consumer rule.docs/reference/contracts/projection-envelope-contract.md(indexed), plus aProjection Envelopesection indocs/status-data-contract.md.Migration economics
statusalready makes about 106 TS calls andglobal-summaryabout 370 on a real machine, so the TS runtime is already a hard dependency of these paths.Next (not in this PR)
global-todos,global-risks, quota should-run, the review packet, and Decision Context source freshness (which lines up with the freshness work in #5075) should adopt the same envelope, in that order, as they are migrated.Note:
loopx/extensions/presentation.pyalready usesprojection_envelopeas an error-context label for extension surface records. That is a different schema and never appears as a payload key; the two do not collide.Validation
npx tsc --project tsconfig.control-plane.json --noEmit: cleannpm run -s test:control-plane: 3115 tests, 0 failures (7 new envelope tests: fresh read, per-window staleness at serve time, unreadable/partial/required-missing sources, incomplete vs truncated-only vs undercounted coverage, cache serve, upstream composition withvia, decoder rejections)tests/test_projection_envelope.py: 9 new tests (registry, goal and unknown-goal coverage, path-free output, cache replay restamp, cache miss on missing or tampered envelope, global-summary incomplete vs complete, global-gates with unavailable quota and missing upstream)test_delegation_result_use×2 and the registry I/O census ×2) all reproduce on the unmodified merge base. After rebasing, the census manifest was regenerated for the two line references this PR moves, and the census tests pass.examples/semantic-vocabulary-drift-smoke.py,examples/docs-governance-smoke.py,git diff --check: okloopx check --scan-pathon every touched file: errors=0examples/repository-hygiene-smoke.pyfails withrelease timeline is missing version entries: v1.2.0. This also fails on unmodifiedorigin/mainand is unrelated to this PR.