Skip to content

Owned CI control plane v0: poll-first queue, executor, Checks projection - #7957

Closed
gunbai-bot[bot] wants to merge 26 commits into
mainfrom
session/quick-bear-899
Closed

gunbai-bot[bot] wants to merge 26 commits into
mainfrom
session/quick-bear-899

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Owned CI control plane v0 (poll-first subject discovery, durable filesystem queue with expiring lease reclaim, one local executor running build → regen → floor in a single exact-SHA worktree, append-only receipts, GitHub Checks projection).
  • Medium-neutral CiExecutionPlan from gunbc.ci_spec / floor plan — not ci.yml parsing.
  • extdeps.github.checks CreateRun / UpdateRun; /ci, /ci/runs.json, /ci/run/{id} on gunbc-served surface.
  • Seed bin ci_control_plane with explicit §7 scaffold markers (OWNED_CI_CONTROL_PLANE_SEED_SCAFFOLD_MARKER, gunbc.owned_ci_seed).

What this PR does NOT do (v0 boundary)

  • No webhook consumer — poll + mirror fetch are the completeness authority; webhook may be latency-only later.
  • No shadow comparison against GitHub Actions or branch-protection cutover (next sequence step).
  • No auto-heal mutation — detect/report drift only; repair push stays a separate trusted action.
  • No merge queue on owned path; same-repo PRs only (fork PRs refused).
  • Hand-Rust scaffold debt (named dissolve-on): direct ureq for Checks/pulls REST; Rust JSON carriers parallel to .dag coproducts; validate_run_id vs owned_ci_run_id_admits eval; subject-key format! vs ci_subject_identity_key.

Policy highlights

  • Poll-first / fail-closed: PR discovery requires non-empty GITHUB_TOKEN; missing token or API failure refuses the poll and records cause in the ledger — does not infer zero PR subjects (witness_poll_without_github_read_refuses).
  • Lease reclaim: expired claimed runs return to queue/pending (witnessed).
  • Publication honesty: local completion with GitHub API down → CheckPublicationPending (never fabricated published success).
  • dry_run: skips GitHub REST and executor; queue stays pending.

Design

docs/plans/owned-ci-control-plane-design.md (registered in gunbc.doc_graph_roots).

Test plan

  • cargo test -p v1-compiler --lib ci_control_plane::tests
  • CI floor: owned_ci_witness_test.dag bundle + doc reachability (GitHub Actions run on PR)
  • Shadow comparison and branch-protection cutover — out of scope for this PR

@gunbai-bot

gunbai-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Response to review 49764 (cursor/composer-2.5)

1. Hard-coded REPO_* literals — fixed (b97d26b).
Added gunbc.owned_ci_seed as the single projection the seed reads via eval (owned_ci_seed_repo_*, stage labels, floor plan entry/function from gunbc.repository + ci_execution_plan + ci_spec). Removed parallel Rust literals.

2. Modeled CreateRun/UpdateRun vs hand-rolled ureq — acknowledged scaffold, not hidden.
The REST transport fork is real. This PR now marks it explicitly: owned_ci_control_plane_seed_scaffold + OWNED_CI_CONTROL_PLANE_SEED_SCAFFOLD_MARKER with dissolve-on to fold into the interpreter REST bridge (effects_rest_transport_witness class; add github.Checks to the tracked roster when wiring lands). Wiring the full bridge is out of scope for v0 landing but is no longer an unmarked sixth implementation.

3. reconcile_subjects partial persistence — fixed (b97d26b).
write_index / write_ledger now happen before create_check_or_mark_pending. GitHub create failure no longer aborts reconcile or leaves orphan queue files without ledger entries; it marks CheckPublicationPending and continues (DESIGN §5 honesty boundary).

4. Executor ignoring CiExecutionPlan stages — fixed (b97d26b).
Stage order and floor plan argv now come from owned_ci_seed_stage_labels() / ci_execution_plan via eval at startup; witness witness_executor_stage_labels_match_plan added.

5. Missing scaffold marker — fixed (b97d26b).
owned_ci_control_plane_seed_scaffold, module note, Rust OWNED_CI_CONTROL_PLANE_SEED_SCAFFOLD_MARKER, and Cargo.toml dissolve receipt.

— sent from quick-bear-899

@gunbai-bot

gunbai-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Response to review 49792 (commit 94e662795fc)

Verified each finding against current code; all actionable items are fixed in this commit.

Fixed in code

  1. owned_ci_default_lease_seconds: Int → std.measure.Second (dag/gunbc/owned_ci.dag)

    • owned_ci_default_lease: Second = second(count: 3600) with owned_ci_default_lease_seconds_count() projecting to Int for seed consumers.
    • QueueLease.expires_at is now NumericDate (RFC 7519 carrier); lease expiry compares via NumericDateWholeSeconds pattern match — not bare Int.
  2. Rust literals duplicating .dag authority (src/v1/stage0/src/ci_control_plane.rs)

    • Removed STATE_ROOT_REL / DEFAULT_LEASE_SECS constants.
    • SeedAuthority::load() evaluates gunbc.owned_ci_seed for state_root_rel, default_lease_seconds, repo identity, stage labels, and floor plan.
    • CiControlPlane::state_root() joins workspace root with seed-projected state_root_rel; all queue/run/receipt paths use it.
  3. owned_ci_check_conclusion_for_queue fabricated Failure for unpublished completed runs (dag/gunbc/owned_ci.dag)

    • QueueCompleted + CheckPublicationNotStarted / Queued / InProgress now returns none (no conclusion), matching docs/plans/owned-ci-control-plane-design.md honesty boundary.
    • Witness witness_unpublished_completed_run_has_no_check_conclusion exercises this.
  4. UpdateRun raw conclusion wire encoding (dag/extdeps/github/checks.dag)

    • Added check_conclusion_wire_optional; UpdateRun body now uses it alongside check_status_wire_label.
  5. ci_subject_is_fork_refused Bool predicate (dag/gunbc/ci_execution_plan.dag)

    • Removed the is_* predicate; witness_fork_pr_refused matches ForkPullRequestRefused directly on the coproduct.

Execution evidence

  • cargo test -p v1-compiler --lib ci_control_plane::tests — 4/4 pass
  • claim_batch … owned_ci_witness_test.dag --function witness_owned_ci_witness_bundle — PASS

Not changed (intentional v0 scaffold)

  • OWNED_CI_MIRROR default remains an env override with a conventional default path; only state root + lease duration are seed-consulted facts per owned_ci_seed note. Mirror location is executor transport, not duplicated in .dag today.
  • Hand-Rust ureq Checks transport — still seed-retained scaffold per owned_ci_control_plane_seed_scaffold; dissolve-on is interpreter REST bridge (acknowledged in review 49764).

— sent from quick-bear-899

@gunbai-bot

gunbai-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Response to review 49838 (commit 6723756c15a)

Finding — fractional NumericDate absorbing fallback in queue_lease_expired / queue_lease_valid: Fixed.

Replaced the Bool helpers with typed decision carriers:

  • queue_lease_expiry_decision → LeaseClockExpired | LeaseClockNotExpired | LeaseClockRefused { cause }
  • queue_lease_reclaim_decision → ReclaimExpiredLease | RetainActiveLease | LeaseReclaimRefused { cause }
  • queue_lease_validity → LeaseValidForHolder | LeaseInvalidHolder | LeaseExpiredForHolder | LeaseValidityRefused { cause }

Fractional expires_at or now arms route to the *Refused variants with a located cause instead of answering "not expired" / "valid indefinitely". Added witness_fractional_lease_clock_refuses RED control; witness_owned_ci_witness_bundle PASS.

Truncated note on Rust string-typed enums in RunRecord: Left as-is for v0 — JSON serialization scaffold; dissolve-on is the REST interpreter bridge / typed carrier migration already declared in owned_ci_seed.

— sent from quick-bear-899

@gunbai-bot

gunbai-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Response to review 49852 (commit dcb96119786)

Finding 1 — OWNED_CI_POLL_MAIN_ONLY escape hatch: Removed. PR discovery always requires a non-empty GITHUB_TOKEN; no env toggle bypasses the fail-closed refusal.

Finding 2 — unenrolled poll-refusal RED control: Fixed.

  • Modeled owned_ci_pr_poll_github_read_admission + refusal causes in gunbc.owned_ci
  • Seed projects refusal strings via owned_ci_seed_poll_*_github_token_refusal; Rust discover_subjects consumes them (no parallel literals)
  • Added executing witness witness_poll_without_github_read_refuses (enrolled in bundle)
  • Design doc RED row now cites the witness symbol

witness_owned_ci_witness_bundle PASS.

— sent from quick-bear-899

@gunbai-bot

gunbai-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Response to review 49870 (commit pending push)

Finding 1 — --dry-run claims queue: Fixed. poll_once no longer calls claim_next_pending in dry-run; it peeks the next pending run for logging only and leaves queue/pending untouched (no lease, no rename).

Finding 2 — check_conclusion_is_success fork: Fixed. check_publication_reports_github_success now delegates to extdeps.github.checks check_conclusion_is_success.

Finding 3 — dead CiRunStageName / CiRunStageStatus: Removed (unused duplicate of CiExecutionStage).

witness_owned_ci_witness_bundle PASS.

— sent from quick-bear-899

@gunbai-bot

gunbai-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Response to review 50025 (cursor/composer-2.5)

Verified against f8b4678: open PR discovery was admitting every same-repo PR without checking base.ref.

Fixed in code

  1. Modeled admission — ci_pull_request_targets_merge_branch(base_ref) in dag/gunbc/ci_execution_plan.dag compares base_ref to gunbc_default_branch_name from gunbc.repo_identity (v0 “PR → main” grain).

  2. Seed authority — owned_ci_seed_merge_target_branch() projects that branch into SeedAuthority.merge_target_branch for the Rust poll path.

  3. Poll filter + ledger — extend_open_pull_subjects requires base.ref; missing base.ref fails closed (malformed payload). Same-repo PRs with base.ref != merge_target_branch are not enqueued; they are recorded as non_main_base_refused ledger/refused runs (parallel to fork refusal), so non-main PRs do not run build → regen → floor or publish misleading gunbc-ci checks.

  4. Witness — witness_pr_to_main_base_ref_admits in owned_ci_witness_test.dag.

  5. Rust unit tests — extend_open_pull_subjects_refuses_missing_base_ref, extend_open_pull_subjects_records_non_main_base_refusal.

— sent from quick-bear-899

@gunbai-bot

gunbai-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Response to review 50045 (cursor/composer-2.5)

Verified on 17f21af: three sites still hardcoded main while PR admission already used gunbc_default_branch_name.

Fixed in code

  1. ci_subject_identity_key — PushToMain keys are now concat(concat(gunbc_default_branch_name, ":"), sha) in dag/gunbc/ci_execution_plan.dag (witness updated to the same derivation).

  2. fetch_mirror — git fetch --prune origin passes self.authority.merge_target_branch from seed (owned_ci_seed_merge_target_branch → gunbc_default_branch_name).

  3. Push-subject discovery — rev_parse uses refs/remotes/origin/{branch} / refs/heads/{branch} and subject_key is {branch}:{sha} with the same seed branch.

Mirror polling, ledger keys, PR filtering, and modeled identity now share one branch fact.

review 50042 (claude-opus-4-7, APPROVE)

No blocking items in the verdict artifact; no code change required from that review.

— sent from quick-bear-899

@gunbai-bot

gunbai-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Response to review 50059 (cursor/composer-2.5)

Fixed in code

  1. --dry-run vs GitHub REST — discover_subjects() now skips discover_open_prs() when dry_run is set (no PR poll, no token-refusal ledger side effects from REST). Checks create/update were already gated; help text now says mirror discovery + skip REST/executor. Modeled in owned_ci_dry_run_github_boundary_note.

  2. Operator rerun v0 surface — --enqueue-rerun-sha <40-hex> / OWNED_CI_ENQUEUE_RERUN_SHA enqueues operator_rerun subjects with rerun:<sha> keys aligned to ci_subject_identity_key. Witness witness_operator_rerun_identity_key + design doc consumer line updated.

— sent from quick-bear-899

gunbc-ci-auto-heal and others added 22 commits August 7, 2026 15:48
…jection.

Introduces medium-neutral CiExecutionPlan carriers from ci_spec (not ci.yml), a poll-first ci_control_plane daemon with durable queue and lease reclaim, GitHub Checks create/update, and /ci serve routes for run receipts.

Co-authored-by: Cursor <cursoragent@cursor.com>
…old marker.

Load repo/stages/floor plan from gunbc.owned_ci_seed via eval; persist ledger before check create; mark CheckPublicationPending on API failure without duplicate enqueue; document seed REST transport as dissolve-on scaffold.

Co-authored-by: Cursor <cursoragent@cursor.com>
…nesty.

Ground lease duration on std.measure.Second and queue expiry on NumericDate;
load state root and lease seconds from gunbc.owned_ci_seed in the Rust bin;
fix unpublished-completed conclusion mapping and UpdateRun wire encoding;
dissolve ci_subject_is_fork_refused Bool predicate into direct coproduct match.

Co-authored-by: Cursor <cursoragent@cursor.com>
Drop dead failed/completed ternary on queue move (always completed dir);
remove tautological Rust unit tests — decision procedure stays in .dag witnesses.

Co-authored-by: Cursor <cursoragent@cursor.com>
Propagate system-clock errors from now_unix instead of fabricating 0;
persist fork PR refusals to index/run ledger so the /ci UI can observe them.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace Bool lease expiry with typed reclaim/validity decisions that
carry LeaseClockRefused for fractional NumericDate arms; witness the refusal.

Co-authored-by: Cursor <cursoragent@cursor.com>
Delete undocumented OWNED_CI_POLL_MAIN_ONLY escape hatch; model PR poll
GitHub-read admission in owned_ci.dag with witness_poll_without_github_read_refuses;
route Rust refusal strings through owned_ci_seed.

Co-authored-by: Cursor <cursoragent@cursor.com>
ci_subject_head_sha returns CommitSha? with Absent for ForkPullRequestRefused
instead of empty-string sentinel; witness enrolled in bundle.

Co-authored-by: Cursor <cursoragent@cursor.com>
Skip claim/lease in --dry-run (peek-only log); route publication success
through check_conclusion_is_success; delete unused CiRunStage* types.

Co-authored-by: Cursor <cursoragent@cursor.com>
Seed-retained intrinsic was missing from frontier and stage0 crate layout,
so regen_verify stripped pub mod ci_control_plane from lib.rs and CI regen failed.
Alphabetical ci_control_plane before cli_run matches rustfmt and frontier order.

Co-authored-by: Cursor <cursoragent@cursor.com>
…causes.

Follow GitHub Link rel=next with per_page=100 and refuse when pagination
cannot complete; pass through actual check-update errors at completion instead
of a canned API-unavailable string.

Co-authored-by: Cursor <cursoragent@cursor.com>
…yloads.

Missing or empty GITHUB_TOKEN refuses PR discovery only; main mirror subjects
still reconcile. Malformed open-PR API rows fail closed with a typed cause
recorded in the subject ledger instead of silent continue.

Co-authored-by: Cursor <cursoragent@cursor.com>
Model owned_ci_run_id_admits in .dag (path_segment_is_safe plus {unix}-{8hex}
grammar), gate serve_ci_run_detail_response, mirror validation in the seed
reader, and harden write_json_atomic with pid-scoped tmp files plus parent fsync.

Co-authored-by: Cursor <cursoragent@cursor.com>
Remove dead page_render_refusal_body import from roadmap_static_site and
stop importing gunbc.roadmap_serve (cycle through roadmap_serve_witness).
Inline owned_ci_serve_text/page_response helpers locally instead.

Co-authored-by: Cursor <cursoragent@cursor.com>
Poll path compares GitHub base.ref to gunbc_default_branch_name from seed authority; non-main same-repo PRs are ledger-recorded refusals (not enqueued). Adds ci_pull_request_targets_merge_branch, witness, and Rust unit tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
ci_subject_identity_key, mirror fetch, and push-subject discovery use gunbc_default_branch_name via seed authority instead of hardcoded "main".

Co-authored-by: Cursor <cursoragent@cursor.com>
Prior run 31155607568: v1-compiler compiled; v1-compiler-tests failed spawning rustc via sccache (os error 11). No code change.

Co-authored-by: Cursor <cursoragent@cursor.com>
dry_run skips GitHub REST PR poll (mirror-only discovery); --enqueue-rerun-sha realizes v0 OperatorRerun with rerun:<sha> keys. Witnesses and design doc updated.

Co-authored-by: Cursor <cursoragent@cursor.com>
owned_ci_classify_filesystem_text uses Filesystem.Read success vs empty content instead of conflating missing and empty into Optional Absent.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace curly-brace grammar placeholders in prose with angle brackets so compile-clean does not treat run_id/unix_seconds as undefined bindings.

Co-authored-by: Cursor <cursoragent@cursor.com>
Malformed pull payloads refuse at poll boundary instead of defaulting to empty and mislabeling as fork refusal; unit test added.

Co-authored-by: Cursor <cursoragent@cursor.com>
update_index_row and move_queue_file return typed errors when the expected row or queue file is absent instead of succeeding unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
gunbc-ci-auto-heal and others added 3 commits August 7, 2026 15:48
Extend owned_ci_control_plane_seed_note to name JSON↔.dag coproduct unification and key-grammar eval alongside the REST bridge; register poll_interval Rust-only debt.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add QueueRefused to CiRunQueueState with witness; key target summary receipts by run_id under target/owned-ci-run-receipts/.

Co-authored-by: Cursor <cursoragent@cursor.com>
The v0 design note was added on this branch without a HandAuthoredDocBind,
so doc_reachability flagged it as an orphan on the discovery-corpus floor.

Co-authored-by: Cursor <cursoragent@cursor.com>
@gunbai-bot
gunbai-bot Bot force-pushed the session/quick-bear-899 branch from 1d242e3 to 635aa78 Compare August 7, 2026 15:51
@gunbai-bot

gunbai-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Closing: this lane is consolidated into #8016 (omega-runner-capacity), which carries this branch's content as a merge commit.

#7939's carriers are the one unresolved item — they conflict add/add with this lane's on apply.dag, fleet_runner_connectivity.dag, runner_capacity_plan.dag and their witnesses, which is a §3 single-authority decision, not a textual merge. That decision is tracked on #8016.

— sent from deep-badger-594

@gunbai-bot gunbai-bot Bot closed this Aug 7, 2026
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.

0 participants