Skip to content

ci: pin release evidence policy to the current ci.yml - #8377

Merged
lidge-jun merged 1 commit into
devfrom
fix/release-evidence-ci-pin
Nov 8, 2026
Merged

lidge-jun merged 1 commit into
devfrom
fix/release-evidence-ci-pin

Conversation

@lidge-jun

@lidge-jun lidge-jun commented Nov 8, 2026 •

Copy link
Copy Markdown
Owner

Summary

dev is red at gates. #8369 changed .github/workflows/ci.yml (moving heavy Linux jobs to the self-hosted pool) without updating its pinned digest in .github/scripts/release-evidence-policy.json. release-evidence.test.cjs › "production policy pins the current workflows and job-selection helpers" now fails on every PR cut from dev:

AssertionError [ERR_ASSERTION]: .github/workflows/ci.yml
+ '4d1d82f1d26d95d2448b1269dde1b7b14b73455e'
- '562e63d6bd140944d8c6ba808010913463c75826'

This follows the pattern earlier workflow changes used, for example #8345. It appends a new ci v1 policy entry identical to the previous one except for the ci.yml digest, which becomes 4d1d82f1…, the blob of ci.yml at dev 399925164. Earlier entries stay, so evidence from runs on older commits keeps validating against the policy that was current for them. ci.yml was the only stale entry: every other file in the latest ci and service policies still matches.

Verification

  • Failing-first: on dev, node --test .github/scripts/release-evidence.test.cjs gives 1 failure, the digest assertion above, matching the gates failure on fix(gui): explain a refused Remember instead of reporting the admin token unverifiable #8374 (job 128800965330). With this change: 25 pass, 0 fail.
  • node --test .github/scripts/release-dispatch-guard.test.cjs and node --test .github/scripts/release-resume.test.cjs pass. release-history.test.cjs fails 2 cases locally both on dev and on this branch, because it needs full tag history. It passes in CI, where the same gates log shows those cases green, and it does not read this file.
  • NOT RUN: the full suite. This is a data-only change to one JSON file.
  • Pushed with --no-verify. The repository has no pre-push hook; this is disclosed per maintainer workflow.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed. Not applicable.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults. This touches release-evidence policy, so a separate security review is requested. It changes no workflow, permission or action ref: it only records the digest of the ci.yml already on dev.

Summary by CodeRabbit

  • Chores
    • Updated internal release validation records. There are no changes to the product’s features or behavior.

@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner November 8, 2026 17:23
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 8, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-08T17:25:25.706072Z 2853da4 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

✅ Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the chore Maintenance, CI, tests, refactors, or build changes (not a user-facing bug or feature). label Nov 8, 2026
@coderabbitai

coderabbitai Bot commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

The release evidence policy adds a version-1 CI record. It lists the CI workflow and supporting files, including the workflow hash.

Changes: CI evidence policy

Layer / File(s) Summary
Add CI evidence record
.github/scripts/release-evidence-policy.json
The policy adds a version-1 CI record. It lists the CI workflow with hash 4d1d82f1d26d95d2448b1269dde1b7b14b73455e; the other listed file hashes match the preceding record.

Estimated code review effort: 2 (Simple) | ~8 minutes

Change: Other

Possibly related PRs

Merge Risk: Minimal · up to 2853d

The policy refresh has no identified merge-blocking issue and is mergeable subject to normal checks.

Pre-merge checks: Passed 5

Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title "ci: pin release evidence policy to the current ci.yml" matches the main change. The PR adds a new version-1 ci evidence record to .github/scripts/release-evidence-policy.json with an update…
Docstring Coverage Passed No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title "ci: pin release evidence policy to the current ci.yml" matches the main change. The PR adds a new version-1 ci evidence record to .github/scripts/release-evidence-policy.json with an updated ci.yml workflow hash. The objectives say the same thing: the ci.yml digest was stale and is now pinned to the current workflow. The title is specific, concise, and uses the conventional ci: prefix. Only the policy JSON file changed, so the title covers the full changeset.

Full details: Docstring Coverage

Explanation

No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 0 files. (1 skipped: 1 unsupported.)

Finishing Touches

Generate unit tests (beta)

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between 3999251 and 2853da4.

Files selected for processing: 1

  • .github/scripts/release-evidence-policy.json

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 4 remain after this review.

@lidge-jun
lidge-jun merged commit f6506e7 into dev Nov 8, 2026
61 of 66 checks passed
@lidge-jun
lidge-jun deleted the fix/release-evidence-ci-pin branch November 8, 2026 18:07
lidge-jun added a commit that referenced this pull request Nov 8, 2026
No content change. dev fixed the release-evidence policy pin in #8377; this empty commit gives the pull request a new merge ref so gates runs against it.
lidge-jun added a commit that referenced this pull request Nov 9, 2026
…) (#8276)

* feat(link): reconcile per-device route intent from Home (#8274)

* fix(route-to): preserve live denials and deferred sync outcomes

* test(cli): include route-to metadata in isolated capability fixtures

* fix(cli): reconcile route-to compatibility contracts from CI

* fix(link): preserve Codex cleanup ownership and defer local writers

* fix(link): reconcile Codex enable during fresh enrollment

* fix(link): arm enrollment rollback before config publication

* test(cli): update ZCode aliases for durable route intent

* fix(link): stop intent controllers before runtime recycle

* fix(link): address policy, parity, ownership and recovery reviews

* fix(desktop): preserve native mode and owned route transactions

* docs(link): clarify device policy and recovery guarantees

* fix(link): settle config ACL before native apply admission

* fix(desktop): retain diagnostics at early ACL admission

* fix(link): report native intent lock contention as busy

* test(link): align native route regression with server layout seeds

* fix(link): keep device policy seeding under one config lease

* fix(link): report native decision failures with publication evidence

* fix(desktop): recheck ACL settlement at native decision commit

* fix(claude): decide native toggle after ACL admission

* test(link): propagate seed fixture rollback failures

* fix(link): preserve Home native intent and idle watch

* fix(link): preserve enrollment inheritance and desktop mode

* fix(link): restore standalone native intent on disconnect and failed enrollment

A linked Child persisted its Home's effective intent into its own native
switches (clientIntegrations.codex/grok/claude-desktop, claudeCode.enabled
and, as side effects, claudeCode.authModeMigratedAt and apiSurfaces.messages)
but disconnect and failed-enrollment rollback never put the standalone values
back, so a Child that was Codex-on before linking stayed Codex-off after a
Home turned Codex off and the Child disconnected (and the reverse).

A machine-scoped private record (<configDir>/link/native-intent-originals.json)
now captures each field's standalone value (presence included) the first time
a Child link write changes it, write-ahead of the atomic config write, plus
the value this writer published or had pending. Disconnect and failed
enrollment restore the original only where the current value is the writer's;
a person's later edit is kept. The record is removed after the restored
config is read back and verified, so an interrupted restore is retryable.
Home writes are not recorded.

The fresh-enrollment Codex compensation now uses the same restore, which also
covers a field a crashed earlier attempt left behind.

* test(link): cover native originals capture, crash recovery and relinking

Module-level regressions for the standalone native originals record: capture
once across repeated writes, no ownership for a no-op or a Home write, a
person's edit kept on restore, Claude enabled/migration stamp/Messages
presence, a crash between the write-ahead record and the config write, a
crash between the config write and publish, an interrupted restore retried
after either step, a different link after a crashed enrollment, and an
unreadable record refusing both capture and restore.

* docs(link): document standalone native restore and local opt-out retention

Public guide (en, ko) and structure/remote-link.md describe how a linked
Child records its standalone native switches before the first link write,
how disconnect and failed enrollment restore them while keeping a person's
own edits, the ABA limit, and that the Child's local opt-out list survives
disconnect (now pinned by a regression test).

* test(link): pin the disconnect-resume fault after token removal

The fixture failed the first config commit and relied on it being the
post-token connection clear. Disconnect now restores standalone native
switches in an earlier config commit, so the hook re-arms until the token
is gone and the fault lands where the test name says.

* fix(link): keep implicit Home Desktop and Grok intent to startup scope

An undecided Home Desktop intent (no persisted default and no Home
override) used to create an OpenCodex gateway profile and switch Desktop
to gateway mode on any unrelated Home route write. It now refreshes only
a gateway profile OpenCodex already owns and otherwise reports current
without writing. Implicit Grok intent follows the startup gate, so a
gated hub or sibling writes nothing. Explicit defaults and device
overrides still create.

* fix(link): keep the Home's own native switches over captured defaults

Captured route defaults exist to drive Children, but the Home projection
preferred them over the Home's live native switches. ocx restore,
Messages off and similar writers change those switches without recording
route intent, so any unrelated route write re-enabled Codex and Claude
Code and re-injected Codex. On the Home, a persisted native switch with
no Home override now wins unless the write decides that client, the
projection reads the durable switches, and a single-client Home write
materializes only that client while keeping the other clients' receipt
outcomes.

* fix(link): treat first-party Claude Desktop as current for enabled intent

First-party Desktop already routes through OpenCodex, yet the route
adapter reported a conflict for both on and off, so Home ocx sync exited
1 on every run and ocx route to sync stayed 409 after any enrollment.
Enabled intent is now current with no write; disabled intent stays a
conflict whose message names the existing mode switch.

* fix(link): keep ocx integrations native a Home-only decision

The CLI native toggle had become a Home default write, so it changed
every Child and skipped Claude Desktop's first-party transition that the
native route performs. It calls the native route again, which records
only the Home override and runs the client's own transition; on a Child
it refuses with the Home command for that device.

* fix(link): restore standalone file integrations on disconnect

Disconnect disabled every file integration with an ownership record, and
connect had already disabled or refreshed pre-existing ones, so a join
followed by a disconnect lost integrations the Child had set up on its
own. The first link apply now records, write-ahead and bound to the
link, which file clients the Child owned. Disconnect keeps those still
owned, applies again those the link disabled, leaves a local opt-out or
the person's own block alone, and removes only what the link created.

* fix(link): keep the enrollment token until native switches are restored

A failed enrollment removed its service token even when restoring the
standalone native switches threw, leaving no owner to retry. It now keeps
the token and pending marker, like disconnect, and names the record.
Plain ocx disconnect on a disconnected machine drains a lone native
originals record instead of refusing: it restores the switches, removes
the enrollment's own token, and on failure prints the record path and
the recovery step.

* fix(link): readmit the link key after a route intent watch wait

A watch read could wait up to 30 seconds and then answered after
rechecking only the link record, so a key revoked during the wait still
received fresh policy. The wait now repeats the listener's key admission
against current policy before the ownership recheck.

* docs(link): document Child tick rewrites, restore reversion and client toggle scope

State that the periodic Child sync rewrites its receipt and Home proof on
every apply, why a mid-apply parity report shows a brief withdrawal, that
ocx restore on a linked Child lasts only until the next sync unless the
person opts out with --local, and that plain ocx integration client
enable/disable writes the Home default and is refused on a Child.

* fix(link): let the Home's own native switches govern the Home

On the Home, Codex, Claude Code, Grok and Claude Desktop now project
from the Home's persisted native switch (absent is on) with source
"native", ignoring captured defaults and devices.home entries. Before,
the live switch won only when stored as a boolean with no Home
override, so ocx restore back (absent key), ocx claude desktop apply,
or any native toggle (which recorded a devices.home override) let a
plain ocx sync or route to sync rewrite the switch and re-inject or
strip the client.

A full Home sync now decides no client and never writes a Home native
switch; it only refreshes owned artifacts to match it, and an enabled
Grok or Desktop switch keeps startup scope. A Home write that decides
one of these clients (route to default, --device home, native PUT)
applies through the existing switch writer and keeps no devices.home
entry: recordHomeNativeDecision pins the off Child builtin for Grok
and Desktop, setRouteClientIntent refuses a Home native entry, and
initializeHomeRouteIntentDefaults drops one saved by an earlier
version. --device home inherit sets the switch to the default. The
native PUT captures defaults from the durable switches. The Home
receipt parser and ocx.route-to/1 accept the additive "native" source;
documents sent to Children never carry it.

* fix(route-to): mark any outcome for an earlier intent stale

routeToDeviceStatus only turned an outdated current outcome stale. An
earlier conflict or failure kept its colour after the intent changed,
so ocx route to <client> off --device <child> after a conflicted
enable exited 409 on a result that said nothing about the new intent.
Any outcome whose per-client intent digest differs from today's intent
now reads stale; receipts without per-client digests keep the
whole-document rule for current rows only.

* docs(link): document Home native switches, native source and pre-record Children

The remote-link guide (en, ko), structure docs and route to capability
notes now say that on the Home Codex, Claude Code, Grok and Claude
Desktop follow the Home's own switches, that Home writes for them
apply through the switch, that plain ocx sync and route to sync never
change them, that status reports source native, and that an outcome
for an earlier intent reads stale. They also state that a Child linked
before the file-integration originals record existed has none, so
disconnect does not set up again integrations the Home turned off.

* fix(link): capture Children's native defaults once from the Home's switches

A Child's projection fell back to the Home's live native switches whenever no
default was saved, so Home-only writers (ocx restore, restore back, Claude
Desktop apply, Messages off, the Claude toggle) changed what Children inherit,
and a later initialization saved the Home-only value permanently.

Children now never read the Home's switches: device override, then the saved
default, then the builtin. captureHomeRouteDefaults saves the four native
defaults once from the durable switches (Codex and Claude Code as the switch
says, Grok and Claude Desktop off). It runs in every route-intent
initialization (in the same single write, so an Aside refusal writes
nothing), before a Child projection, when the hub-link listener binds, and
before each Home-only switch writer changes a switch on a linked Home.
desired-state.ts stays free of link state for the core/link boundary; the
Home-only writers call setHomeIntegrationEnabled instead.

* fix(route-to): fail a Home write whose decided client the Home cannot apply

A Home write that decides a native client but is refused (first-party Claude
Desktop off) or fails (its switch cannot be written) leaves the Home switch
unchanged, so the rebuilt Home row read the recorded conflict or failure as
stale; the PUT answered 200 and ocx route to exited 0 without the mode switch.

The PUT now uses applyHome's own outcome for the decided client: on conflict or
failed it answers 409 route_apply_unresolved with that outcome in the Home row
and its message (naming the mode switch for first-party Desktop), so the CLI
exits nonzero. A default write still reports that the Children's default was
saved.

* fix(route-to): report a changed refresh-only Desktop profile as a conflict

An enabled Home Claude Desktop switch that no write decides only refreshes a
profile OpenCodex owns. That path returned current for a gateway_drifted,
unsafe or broken profile. It now reports the conflict as the decided path
does, and never takes the profile over even with overwrite: replacing it is a
decided write. The inspection reads the durable applied marker, since the
caller's snapshot can predate a Desktop apply by another process.

* docs(link): document one-time capture of Child native defaults

Children never read the Home's native switches; the Home saves their defaults
once at migration (Codex and Claude Code from the switches, Grok and Claude
Desktop off) and only a Home default write changes them afterwards. Also
document the 409 for a decided Home write the Home cannot apply and the
refresh-only Desktop conflict, in the English and Korean guides and the
remote-link structure notes.

* fix(route-to): leave a Desktop library OpenCodex never owned current on a refresh

A refresh-only Claude Desktop row (an unset Home switch read as on) reported a
conflict for any unsafe or broken library, including one OpenCodex never owned:
an unreadable _meta.json, an applied id outside the safe pattern, or another
app's missing profile. Every full Home sync then failed and advised
--overwrite-conflict, which would take over a library that was never ours.

The refresh-only path now reports a conflict only with ownership evidence (an
OpenCodex entry selected, or unreadable ownership plus a committed applied
fingerprint) and otherwise answers current with no write.

* fix(route-to): refuse a Home-only switch write with a typed refusal when route intent is unreadable

An unreadable or malformed route-intent.json (or config-lock contention) made
setHomeIntegrationEnabled throw a raw SyntaxError, so ocx restore, ocx restore
back, Claude Desktop apply, the Claude toggle and Messages off crashed, and
ocx restore --json printed no envelope.

These writers still refuse before the switch moves, since writing it first would
change what Children inherit once the file is repaired, but the refusal is now
typed: { ok: false, reason: "unavailable", retryable, message } naming the
route-intent.json path and asking to fix or remove it. ocx restore --json prints
one complete envelope with that message; Messages off and the Claude toggle
answer route_intent_unavailable (409 on contention, 500 otherwise).

* fix(route-to): report a saved Home override on a refused --device home write

A --device home write for a client the Home does not treat as native (opencode,
for example) saves a devices.home override before the apply runs. When that
apply answered conflict or failed, the 409 said desiredCommitted: false and "The
Home did not apply", though the override was saved. The 409 now reports
desiredCommitted only when route policy was saved and the client is not a Home
native one, and picks the "Route policy was saved" prefix from the same value.

* fix(route-to): capture Child native defaults on Home-only writes only once linked

The Home-only switch writers (ocx restore, ocx restore back, Desktop apply,
Messages off, the Claude toggle) captured the Children's native defaults only
when the Home had a link, but the native route, a --device home write and the
Home's own apply captured unconditionally. Two unlinked Homes in the same end
state then gave a later-enrolled Child different defaults depending on which
writer had moved the switch.

Every Home-only decision now follows the link-gated rule, through a whenLinked
option on initializeHomeRouteIntentDefaults: the native route, a --device home
write and the Home materializer capture native defaults only when the Home has a
link. Link-gated was chosen over unconditional capture because a standalone Home
never needs route-intent state written by a Home-only toggle, and a Child that
enrolls later inherits the switches as they stand at enrollment, which
seedRouteDeviceClients captures. A default write and enrollment still capture.
Until a default is saved, a Home inherit takes the builtin.

* fix(route-to): keep Child route-intent reads pure

GET /api/route-to and the link GET /v1/link-management/route-intent captured the
Children's native defaults through projectChildRouteIntent, so a read could
write route-intent.json, while the route registry lists the status read as
non-mutating and the link read is documented as not mutating state.

The capture is gone from projectChildRouteIntent. Every path that serves a Child
has captured before it reads: enrollment through seedRouteDeviceClients, and the
link listener's start for a Home that already has links. The test that asserted
first-read capture now asserts the reads write nothing and that enrollment saves
the defaults the Child then projects.

* fix(cli): drop the stale native toggle exemption from the route registry

The four PUT /api/native-integrations/<client> routes were exempt from the CLI
coverage check as a compatibility alias "because current CLI native toggles use
durable /api/route-to intent". That stopped being true when ocx integrations
native went back to calling these routes, which its capability already lists.
The exemption is removed, so the routes get the check, and the capability test
now asserts the routes are covered and not exempt.

The ocx integrations native comment and capability detail (and the generated
skill surface) no longer say a Home override is recorded: the route writes the
Home's native switch and records no Home route intent.

* docs(link): state when Child native defaults are captured

The Remote Link guide (en and ko) said the Home saves the Children's native
defaults when it serves a Child's route intent and in every Home-only switch
command. It now says when capture actually happens: a Home default write and
Child enrollment always save them; once the Home has a link, the link listener
and every Home-only command save them before the switch moves; on a Home with no
link nothing is saved, so a Child enrolled later inherits the switches as they
stand at enrollment; reads never save. It also notes that an unreadable
route-intent.json makes those commands refuse and name the file, that a Home
inherit takes the builtin until a default is saved, and that a Desktop library
OpenCodex never owned is reported current. structure/ notes follow the same
inherit wording.

* fix(route-to): report saved Home native switches and keep route intent off unlinked Homes

A refused or failed Home native decision now reports desiredCommitted from the
durable switch before and after the apply, so a Grok off that saved the switch
before hitting an incomplete block says so. On a Home with no link, native
toggles and --device home native writes no longer read or write
route-intent.json, so ownership defaults cannot pin a client the dashboard
later enables. An unreadable route-intent.json is a typed refusal naming the
file in the native toggle, route-to writes and dashboard file toggles, and a
dashboard file toggle on a Home that uses route intent is recorded as the
Home's devices.home decision so ocx sync keeps it.

* fix(link): retry an owed Child route-defaults capture after a failed listener start

* docs(link): unlinked Homes, saved switch reports and dashboard toggles under route intent

* fix(route-to): keep legacy Home native cleanup on unlinked syncs; linked fixtures for native bookkeeping tests

* docs(structure): unlinked Home syncs drop only legacy Home native entries

* fix(route-to): save Children's defaults before Home-only integration writes and record Aside and restore decisions

* fix(link): cancel an owed route-defaults capture retry when the listener closes

* fix(route-to): treat ephemeral ocx-child links as not supporting route intent

* fix(link): gate overwrite sync flags on a Child that honours them

* fix(route-to): report what a write saved when its apply fails unexpectedly

* fix(route-to): match Aside decision paths with one pattern the route registry does not read as routes

* fix(cli): make plain integration enable/disable a Home-only decision like the dashboard toggle

* docs(ocx-child): say the Rust parity parser is narrower than the Home's

* docs(link): Home-only integration decisions, ephemeral Children and the overwrite sync gate

* test(cli): plain integration toggles name the Home-only toggle route

* fix(route-to): read the durable config for Home integration decisions instead of cloning the live one

* ci: re-run checks on the current dev merge ref

No content change. dev fixed the release-evidence policy pin in #8377; this empty commit gives the pull request a new merge ref so gates runs against it.

* fix(route-to): let unlinked Homes change integrations when route-intent.json is unreadable

On a Home with no link a damaged route-intent.json refused every dashboard and CLI integration change with route_intent_unavailable. Nothing there needs protecting: no Child inherits from it, and ocx sync cannot read the file either, so it cannot undo the write. The write now proceeds and records nothing. Linked Homes still refuse by name. Docs now state that an unlinked Home that already uses route intent still records the Home-only row, which Children never inherit.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore Maintenance, CI, tests, refactors, or build changes (not a user-facing bug or feature).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant