Repository navigation
feat!: make products safe to compose under deferred task grants, fresh grant status, and original receipts - #1976
Merged
Merged
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
6 of 7 tasks
jeremi
force-pushed
the
feat/coordinator-seams
branch
from
October 11, 2026 21:18
287c9be to
a036b41
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a036b41c41
ℹ️ 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".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
jeremi
force-pushed
the
feat/coordinator-seams
branch
from
October 12, 2026 17:29
a036b41 to
8fb7560
Compare
Port discovery releases the socket before the child binds it, so parallel fixtures could reach each other's server. Keep issued ports distinct and report a child that exits before it becomes healthy. Retry on a fresh port, at most three times, when the server's bind is refused. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
… boundary The Casework installer takes raw binaries through v0.32.9 and a bundle carrying the FIPS runtime from v0.33.0, and its test covered Linux only. The fixture now writes a bundle for the later release and binaries that answer --version, and the test mv shim translates the pointer switch in both directions so the forced macOS run also passes on a Linux runner. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
CI services, release recipe roots, and the bregctl, caseworkctl, and messagingctl dev databases pull PostgreSQL, Debian, and Mailpit from the ECR Public Docker Official Images and GHCR mirrors at the same manifest digests. Public help keeps the canonical identities, and retained dev containers accept either exact reference. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Move the task-grant status registry and the exact-status request into registry-platform-oidc, and define the taskGrantStatus entry once as the TaskGrantStatusConfig shared block in registry-platform-config, so every resource server checks a grant through one bounded transport configured by one block. BReg keeps its persisted binding and BReg-only bounds validation and now calls the shared transport. registry-platform-httputil exposes the private_key_jwt identity check and requested-scope validation the transport needs. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
A task template may opt into authorizationMode: deferred for an approved duration of at most seven days; omitted mode stays immediate with its 900-second ceiling. Deferred review grants pin a trigger-maintained assignment generation, so release, reassignment, or completion cannot revive an approval, and retained work-item grants reuse the existing invalidation triggers. The clients, bindings, facade, and OpenAPI carry the mode. Refs #1952 Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
An optional taskGrantStatus registry makes Scheduling obtain a fresh exact status answer from the grant's Casework authority, through the shared platform transport, before every capacity commitment and idempotent replay, with no fallback once configured. Without it, only a grant with at most 900 seconds remaining is accepted. The capacity transaction rechecks the earlier token and grant deadline after lock waits. SCHEDULING-SEC-03 becomes enforced and the SCHEDULING-DEF-01 deferral is closed. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
…commands A caller recovering from a lost response can now observe the retained original receipt for its own key and exact request without submitting the command again: Scheduling serves POST /v1/appointments/receipt under ordinary read authentication, and Messaging serves POST /v1/messages/receipt. Lookup stays scoped to the caller's verified identity, and neither route renders, submits, or claims capacity. The Rust clients, the Node.js and Python bindings, the unified facades, the generated OpenAPI documents, the API reference pages, and the security contracts carry the new routes. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
… in dev sessions bregctl dev derives the generated runtime's principal claim from the compiled access profiles, resolves a `$localClientSubject` fixture marker for `sub` journeys, and binds declared Casework task-grant status services with their own status-only clients. Authored machine-client `grants` give a local client exact registered scopes on other resources through the ThunderID tooling's explicit `ordinary_resource_permissions` allowlist, which stays empty, and bootstrap-only, by default. caseworkctl dev refuses borrowed sessions whose access profiles use `sub` and reports known integration and shared-registration mismatches with a fixed diagnostic category and the clients-file section to correct. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
… change The suite proves that a committed loss of directory membership, holder, or proposal permanently invalidates a task grant while transient writes and atomic replacement do not, and that item erasure removes the grant records. It runs beside the assignment and routing suites against the same PostgreSQL service, and the gates inventory pins the command. Closes #1936 Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
An operator writes an egress allowlist from the help, so the bregctl and caseworkctl dev start help and the messagingctl dev help now name the exact mirror references the session pulls, and tests hold each help to the supervisor's own constant. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Adopters upgrading need the deferred grants, the shared status transport, the Scheduling offline bound, the receipt routes, the stricter BReg status configuration, and the changed client and caseworkctl refusals in one place, with a migration for each breaking change. The changelogs also name the mirror registries each dev session now pulls from, for egress allowlists, and the receipt problem code the Scheduling and Messaging Rust clients gain. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
jeremi
force-pushed
the
feat/coordinator-seams
branch
from
October 12, 2026 21:58
8fb7560 to
1356242
Compare
jeremi
enabled auto-merge
October 12, 2026 22:00
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
An orchestrator that drives Casework, Scheduling, Messaging, and the Base
Registry Engine (BReg) together has to wait for people, survive restarts, and
recover from lost responses. These seams let any orchestrator do that without
taking authority from the products it composes:
transport, configured by one shared block.
submitting the command again.
Nothing here is specific to the Coordinator. The Coordinator PR follows this
one and is the first consumer.
Pieces
Main fixed the BReg client's refusal of
statisticalDatasetsmetadataindependently, so this PR no longer carries its own fix.
Render serve fixtures get distinct ports
Port discovery releases the socket before the child process binds it, so
parallel
registry-renderserve fixtures could reach each other's server. Thefixtures now keep every issued port distinct, retry on a fresh port when
another socket takes theirs before the bind, and report any other child that
exits before it becomes healthy, with its output. Test-only.
The Casework installer test covers macOS on both sides of the bundle boundary
The Casework installer takes raw binaries through v0.32.9 and a bundle carrying
the FIPS runtime from v0.33.0; BReg's installer test already covers its own
bundle, and Casework's covered Linux only. A test now installs a v0.32.9 and a
v0.33.0 macOS release and checks each layout. The fixture writes a bundle for
the later release, and the test
mvshim translates the pointer switch in bothdirections, so the forced macOS run also passes on a Linux runner. Test-only.
Pinned prerequisite images come from digest-identical mirrors
CI services, the release recipe roots, and the
bregctl,caseworkctl, andmessagingctldev databases now pull PostgreSQL, Debian, and Mailpit from theECR Public Docker Official Images mirror and from GHCR. Each image keeps the
same manifest digest, so only the registry endpoint changes. The
bregctlandcaseworkctldev starthelp and themessagingctl devhelp name the exactmirror reference each session pulls, so an egress allowlist can be written from
--help; a test holds each help to the binary's own image constant. A retaineddev container is accepted under either exact reference.
release/OPERATIONS.mddocuments the procedure under"Pull pinned prerequisite images". Digests and the PostGIS exception are listed
under Security review notes.
Shared task-grant status transport and the
TaskGrantStatusConfigblockregistry-platform-oidcgains atask_grantmodule with the exact statustransport that BReg and Scheduling share:
TaskGrantStatusEndpointTaskGrantStatusRegistry, with an offlinevalidate_configuration, plusactivateandcheckTaskGrantStatusClientTaskGrantStatusBindingTaskGrantErrorregistry-platform-configdefines thetaskGrantStatusentry once, as theTaskGrantStatusConfigshared block. It joins the CFG-SCHEMA-5 list inproducts/platform/CONFIG-CONVENTIONS.mdand is registered with theconformance tooling and the canonical shared-block schema. Its doc comments
name no particular authority; Casework appears only as the default.
The block maps onto
TaskGrantStatusEndpointthrough aFromimpl. That impllives in
registry-platform-oidc, becauseregistry-platform-oidcalreadydepends on
registry-platform-configand the reverse dependency would form acycle.
The YAML keys are unchanged, so existing adopter files still load. The block
adds two optional members,
statusScopeandstatusPath. They default toCasework's
casework:grants:statusscope and its/v1/task-grants/{grantId}/statusroute.BReg keeps its persisted binding and its BReg-only bounds validation, and now
calls the shared transport.
registry-platform-httputilexposesvalidate_requested_scopesandPrivateKeyJwtConfig::check_identity, so aconfiguration can be validated without a key, a certificate, or network
access.
AGENTS.mdrecords why Scheduling calling a status endpoint over HTTP is not acrate dependency on Casework. The dependency-direction gate is unchanged.
Casework deferred task grants
A task template can opt into
authorizationMode: deferredwith alifetimeSecondsof at most 604800 (seven days). Omitting the mode keeps itimmediate, with its 900-second ceiling. The preview, the grant view, the Rustclient, the Node.js and Python clients, the facade, and the OpenAPI document
all carry the mode. Approval still names only the template id and version.
Migration 0022 does three things:
casework_task_grants_authorization_windowandcasework_review_task_grants_authorization_window. These bound expiry bymode in elapsed seconds, so database timezone and daylight saving changes do
not affect them.
casework_review_tasks.assignment_generation.BEFORE UPDATEtriggercasework_review_assignment_generation,which maintains that generation.
A deferred review grant pins the generation. A release, reassignment, queue
move, absence-cover change, decision, or completion therefore ends the grant,
and a later reclaim does not revive it. A draft revision does not end it.
Retained work-item grants reuse the existing invalidation triggers.
The approving officer's own source access is checked once, at approval. Later
observations read the source through the service reader, so a withdrawal of
that officer's source access alone leaves a deferred grant active until its
deadline, up to seven days rather than 900 seconds.
TASK_GRANTS.mdstatesthis and tells operators to revoke the officer's live grants, or remove their
Casework eligibility, when source access is withdrawn; either ends each grant
at its next observation.
Scheduling checks fresh grant status before capacity work
The runtime file must now state a top-level
taskGrantStatus. It takes one oftwo forms, and omitting it is refused at startup as
scheduling.runtime.missing-task-grant-status:capacity commitment and every idempotent replay first gets a fresh exact
status answer from the grant's authority. No source falls back: a grant from
an unlisted authority is refused, however short its remaining lifetime.
unchecked-final-fifteen-minutes. Scheduling accepts a grantonly while it has at most 900 seconds left when the request arrives, and
checks no revocation. The keyword names the weakening, so a reader of the
file sees what it accepts.
An empty list is refused, naming both forms. On either path, the capacity
transaction rechecks the earlier of the token and grant deadlines after it
acquires its locks. SCHEDULING-SEC-03 is now enforced, and the SCHEDULING-DEF-01
deferral is closed.
Original receipts without replay
POST /v1/appointments/receiptunder ordinary readauthentication.
POST /v1/messages/receiptunder current ordinary readauthority.
Either route returns the retained original success receipt for the caller's
verified identity, original
Idempotency-Key, and exact original request body.Neither route creates, replays, renders, submits, sends, or claims capacity. A
missing, expired, changed, or refused receipt answers
receipt.unresolved(409). That answer is not evidence that no effect occurred.
Receipt reads are not throttled. Neither route spends or requires a rate
budget, and neither answers
429. Messaging's per-caller budget stays asubmission budget, charged only when a message is accepted, and Scheduling keeps
no request budget of its own on any route. Each read is authenticated, costs
one bounded indexed lookup, and is journaled. An operator bounds an
authenticated flood at the deployment's ingress, as for every other route. The
Messaging recorded decisions and both products' security review notes record
this acceptance.
The Rust clients (
appointment_receipt,message_receipt), the Node.js andPython bindings, the unified facades, the generated OpenAPI documents, the API
reference pages, and the security contracts carry both routes.
Dev sessions wire local task-grant status and resource grants
bregctl dev:$localClientSubjectfixture marker forsubjourneys, on top ofthe one common principal claim main's
bregctl devalready derives from thecompiled access profiles;
taskGrantStatusservices, each with its ownstatus-only client.
A machine client can declare
grantsto get ordinary tokens with exactregistered scopes at other resources. These go through the ThunderID tooling's
explicit
ordinary_resource_permissionsallowlist, which is empty by default.caseworkctl devrefuses a borrowed session whose access profiles usesub.It reports five integration and shared-registration mismatches under their own
codes, each pointing at the clients-file section to correct.
The task-grant invalidation suite runs in CI
The Casework
task_grant_invalidationsuite proves that a committed loss ofdirectory membership, holder, or proposal permanently invalidates a task grant,
that transient writes and atomic replacement do not, and that item erasure
removes the grant records. It now runs in the existing Casework assignment and
routing CI step, against the same PostgreSQL service, and the gates inventory
pins the command. The Casework README lists it with the other suites.
Product changelogs
The BReg, Casework, Messaging, platform, and Scheduling changelogs record each
change under
## Unreleased, the v0.41.0 development section, with a migrationfor every breaking one. The BReg, Casework, and Messaging entries name the
mirror registries an egress allowlist must admit.
Commits
Based on
008968a35, main on 13 October. One commit per piece above, in order,plus the help fix for the mirrors piece:
test(render): give each serve fixture a distinct porttest(casework): cover the macOS installer on both sides of the bundle boundarybuild: pull pinned prerequisite images from digest-identical mirrorsrefactor(platform,breg): share the exact task-grant status transportfeat(casework): approve deferred task grants for delayed workfeat(scheduling): check fresh task-grant status before capacity workfeat(scheduling,messaging): read original receipts without replaying commandsfeat(breg,casework): wire local task-grant status and resource grants in dev sessionsci(casework): run the task-grant invalidation suite on every Casework changefix(dev): name the registry each dev session pulls from in its helpdocs(release): record the task-grant seams in the product changelogsBreaking changes
BReg treats it as an outage and answers
service.unavailable(503) insteadof
precondition.failed(412). A 404 still answersprecondition.failed.The status user agent changes from
registry-breg-task-statustoregistry-task-status.Migration: alert on
service.unavailablefor a misconfigured or revokedstatus client, and match the new user agent in Casework access logs.
taskGrantStatuswhen it reads the file. An invalid entry isrefused as
breg.runtime.invalid-task-grant-statusat/taskGrantStatus.It used to be refused only at activation, as
breg.runtime.invalid-binding. The members are typed.Migration: none for an entry that already activated. A script that matched
the old code must match the new one.
caseworkctl devreports five configuration refusals by their own codesand exits with status 1, where each was
caseworkctl.operational-failurewith exit status 3.
Migration: read exit status 1 and the code.
caseworkctl devrefuses a borrowed session when a Casework accessprofile uses
principalClaim: sub, ascaseworkctl.dev.borrowed-principal-invalid.Migration: use a stable claim such as
registry_principalin every accessprofile.
CaseworkTaskAssertionSourcereports refusals as invalid credentials.A Casework 4xx other than 408 and 429 becomes
TokenError::Invalid(
invalid-credential) instead ofunavailable. A 408, 429, or 5xx staysunavailable.Migration: treat
invalid-credentialas a refusal that needs a new approval,and stop retrying it.
taskGrantStatus. A runtime file without it isrefused at startup as
scheduling.runtime.missing-task-grant-status, at/taskGrantStatus. v0.40.0 had no such member and accepted every unexpiredtask grant. Under the keyword, a grant with more than 900 seconds left
answers
operation.not-authorized(403) and is audited as refused; aCasework immediate grant never lasts that long, so only deferred grants and
longer grants from other authorities meet the refusal.
Migration: list the task authorities under
taskGrantStatus, or writetaskGrantStatus: unchecked-final-fifteen-minutesto keep the offlinefifteen-minute bound without a revocation check.
ReceiptUnresolved.registry_scheduling_core::ProblemCodeandregistry_messaging_core::ProblemCode, which the Rust clients' errors carry,are not
#[non_exhaustive], so an exhaustivematchon either no longercompiles. Only Rust code that matches on the enums is affected.
Migration: add a
ReceiptUnresolvedarm or a wildcard arm.Security review notes
This change touches authentication, authorization, task grants, and release
provenance.
Authorization and task grants
Deferred grants cannot carry Evidence bounds (CASEWORK-SEC-27). Evidence
checks the earlier of the token and grant deadlines but does not check grant
status. Its rule that an assertion stays usable after revocation only until
the immutable grant deadline assumes the 900-second immediate window.
Where the rule is enforced. Core template validation refuses
authorizationMode: deferredwithbounds.type: evidenceascasework.task-template.deferred-evidence.caseworkctl check, packageactivation, and runtime project load all run that validation, and the
generated project schema carries the same condition. The assertion signer also
refuses a stored deferred Evidence grant, so no assertion is signed under a
deferred window.
Negative tests:
deferred_authorization_cannot_carry_evidence_boundsandtask_assertion_refuses_a_deferred_evidence_grant.Deferred grants never widen or extend authority. Short assertions and
execution tokens do not extend the original grant. The PostgreSQL window
constraints hold immediate grants to 900 elapsed seconds and deferred grants
to 604800, whatever the database timezone.
Revival. A release followed by a reclaim, or a reassignment back, cannot
revive a deferred review grant, because the trigger owns the assignment
generation, even against an update that tries to reset it. A missing deferred
counter fails closed. CASEWORK-SEC-18 is backed by
deferred_review_grants_ignore_drafts_but_never_revive_after_responsibility_changes.Deferred regressions. These cover restart, expiry, revocation, release
and reclaim, and daylight saving:
deferred_grants_resume_after_fifteen_minutes_and_restart_without_widening_authoritydeferred_grants_expire_and_revoke_without_extending_the_approved_windowdeferred_work_item_grants_ignore_drafts_but_never_revive_after_release_and_reclaimdeferred_database_window_uses_elapsed_seconds_across_daylight_saving_changesThey simulate elapsed time with synthetic timestamps; none waits sixteen real
minutes.
Grant-status freshness before capacity work
Configured
taskGrantStatus. Every capacity commitment and everyidempotent replay first gets a fresh exact status answer. The answer depends
on what comes back:
operation.not-authorized;service.unavailable.The check is bounded at ten seconds and ends before the capacity transaction
opens. A positive status answer is never cached; only the service credential
is.
Lock waits. Inside the transaction, after lock waits, Scheduling
rechecks the earlier of the token and grant deadlines.
No distributed transaction. Status observation and resource commit are
not atomic. Revocation is effective from the next check onward.
The choice is explicit. A missing
taskGrantStatusis refused ratherthan read as the weaker offline path (CFG-EMPTY-3), and the offline path is a
named keyword rather than an empty list (CFG-EMPTY-2, CFG-NAME-7). The
generated runtime schema requires the member and states both forms.
The 15-minute offline bound. Under
unchecked-final-fifteen-minutes,Scheduling accepts a grant only while
0 < exp - now <= 900seconds. A listturns this path off for every source, so a configured deployment refuses
every grant from an unlisted authority, however short. A long-lived grant is
therefore usable at Scheduling only where its status can be checked.
Tests. The PostgreSQL tests run against a wiremock status authority, not
a running Casework:
configured_task_status_is_fresh_for_a_capacity_commit_and_its_replayinactive_mismatched_and_unavailable_task_status_commit_no_capacityinactive_and_unavailable_task_status_refuse_every_mutation_without_changing_capacity(hold, release, confirm, reschedule, and cancel, each leaving capacity
unchanged)
an_unlisted_source_is_refused_and_never_reaches_the_offline_paththe_offline_path_accepts_at_most_fifteen_minutes_of_remaining_lifetime(at exactly 900 and 901 seconds)
a_refused_attempt_never_resolves_an_original_appointment_receiptoriginal_hold_confirmation_receipt_is_read_by_its_hold_and_keyDatabase-free unit tests cover the verdict and the configuration:
the_offline_path_accepts_only_an_unexpired_grant_with_at_most_fifteen_minutes_left,listed_authorities_refuse_an_unlisted_source_and_an_unbound_grant_without_the_offline_path,a_listed_authority_answer_decides_the_grant,a_missing_task_grant_status_is_refused_naming_both_choices,an_empty_or_unknown_task_grant_status_is_refused_naming_both_choices,the_unchecked_keyword_selects_the_offline_path, andthe_schema_states_both_task_grant_status_choices_and_requires_one.Accepted residuals
spend no rate budget and never answer
429. An authenticated caller thatrepeats one costs a bounded indexed lookup and its audit records per
request. A per-route read budget would be a new configuration surface for a
cost the deployment's ingress already bounds. Recorded in the Messaging
recorded decisions and in both security review notes; the Messaging OpenAPI
document no longer lists
429for the route, andthe_receipt_read_publishes_no_rate_limit_answerholds that.task grants" above. Repeating the approver's own source read at a later
observation would require Casework to retain a credential it must not keep,
so the reliance is stated and bounded by the template lifetime instead.
Exact-subject check
subject binding with the approved one for every grant, including immediate
grants. An immediate grant pins the task revision, which covers the task row
but not the request row. A changed subject therefore invalidates the grant
with reason
eligibilityeven when the task revision is unchanged.Test:
immediate_review_task_grants_refuse_a_changed_request_subject.values exactly, along with the principal, client, resource, purpose, bounds,
and deadline.
Status transport scope and path
Scope. The transport requests one private-key-JWT service credential for
exactly one resource and one scope. The default scope is
casework:grants:status, andstatusScopemust be a single scope token.Path.
statusPathdefaults to/v1/task-grants/{grantId}/status. It must:/;{grantId}segment;The URL is built under the configured
baseUrlonly.Answers. Only a 200 strict JSON document of at most 64 KiB that says the
grant is active and repeats its exact binding is accepted.
credential. It makes the observation unavailable but does not establish that
the grant is inactive. BReg maps it to 503.
Bounds. The whole attempt, including getting the token, is bounded at ten
seconds: five seconds per request and three to connect. BReg's own
five-second bound ends the check first.
Transport identity. The user agent is
registry-task-status.Offline validation.
validate_configurationchecks the same nonsecretstructure without resolving credentials or contacting any endpoint, so BReg
refuses a malformed entry when it reads the file.
Unknown keys. BReg and Scheduling both refuse an unknown key in the shared
block, reporting its path, line, and column (CFG-SCHEMA-8).
Release image provenance
trixie-slim(recipe roots)sha256:a99cfc517144bc59b1978475ec53b46ecabec7e43635402ee5b77cc54cd1b20apublic.ecr.aws/docker/library/debianserve the same digest17.11(CI services, dev databases)sha256:67f41722b7a8cbdb868a44a4995c846eddfdc2973bccb291ce937dce88ad5675public.ecr.aws/docker/library/postgresserve the same digestv1.31.2(CI,messagingctl dev)sha256:74d609a42ec279aa63c6b4622a6fa9b5408d1ad5b1d76a1c4be40a265ce0863ddocker.io/axllent/mailpitandghcr.io/axllent/mailpitserve the same digestpostgis/postgis@sha256:01a6a70e41e6c4467c8f55f6063555ed72db2d6662cd0d571040d42eadaeb6f6manifest digest, so only the registry endpoint changes, not the image bytes.
The strict recipe check and the gate inventory still require the recorded
repository and digest.
digest-identical public mirror could be confirmed.
gcr.io/distroless/cc-debian13isunchanged.
release/OPERATIONS.mdsays to verify the returnedmanifest's SHA256 at the chosen endpoint before changing a pin.
Test evidence
Gate and suite results, run locally on macOS (Apple Silicon)
All results below ran locally on macOS (Apple Silicon); none comes from CI,
which runs on push.
The branch is a linear rebase onto
008968a35, main on 13 October, with no mergecommits. Main's changes since the previous base overlap this branch in four
places, resolved as follows:
bregctl devtakes its local principal claim from main's derivation. Thisbranch's narrower helper, its unit test, its duplicate
DEV.mdsentences,and the principal half of its BReg changelog entry are gone. One
bregctl devunit test keeps main's access profiles as written: thisbranch had rewritten them all to
sub, which now mixes claims and isrefused.
Main's
mvshim also translates-hback to-Tfor a forced macOS run on aLinux runner.
tests and the migration 22 test expect 22 migrations.
The evidence has two layers:
not rerun.
On this head.
cargo fmt --checkcargo check --locked --workspace --all-targetscargo clippy --locked --all-targets -- -D warningson the 22 Rust crates the branch changespostgres-testcargo test --locked --no-fail-faston the same 22 cratesgenerate.py --check-referencesregistry-messaginglib 285 passed, 1 offline configuration checkcheck-config-conformance.py --check-generatedcheck-gates-inventory.pytest_check_gates_inventorytest_release_workflow_structuretest_release_ci_overlaptest_registry_releasecheck_breg_gated_tests.pytest_check_breg_gated_testsPostgreSQL 17:
postgres_transactionscaseworkctllib withpostgres-testtask_grant_invalidationpostgres_commitmentsschedulingctlrecords applyschedulingctlintentsschedulingctlactivationNot rerun on this head:
cargo deny check, the BReg PostGIS suites, theMessaging PostgreSQL suites, the language bindings, Vale, and the release
scripts not listed above. CI covers the workspace,
cargo deny, and thebindings; the earlier results below cover the rest.
Earlier: the review round, on the head before the previous rebase. It
changed Scheduling and Messaging code; in BReg and Casework it changed only
docs.
Scheduling:
cargo clippy --locked --all-targets -- -D warnings, the four Scheduling crates andregistry-messagingregistry-schedulingwithschema,postgres-testcargo test --lockedon the four Scheduling cratesregistry-schedulinglib withschemapostgres_commitmentscheck-config-conformance.py --check-generatedtarget/debugMessaging:
cargo clippy --locked --all-targets -- -D warningspostgres_messages_cliThe Mailpit SMTP suite was not run.
Earlier: the rounds before the review round, on the
a95e1c051base.Where the review round or this head reran a gate, the tables above replace
the earlier count.
Previous head, before the review round:
cargo clippy --locked --all-targets -- -D warningson the 26 crates the branch touchescargo test --locked --no-fail-faston the same crates,registry-renderserve includedregistry-renderserve 23 of 23registry-cli-docssnapshot testcheck-release-source-model.shCargo.lockandproducts/platform/fuzz/Cargo.lockunder--lockedEvery commit passed
cargo check --locked --workspace --all-targetswith nowarnings on
a95e1c051, along with the generator drift checks.Rust workspace:
cargo clippy --workspace --all-targets -- -D warningspasses.cargo test --locked --workspace --no-fail-fast: 9359 passed, 3 failed, 51ignored. Two failures,
registry-evidencectlaccessandjwk_from_pem, are a local macOS issue: the FIPSaws-lcdylib has noLC_RPATH when the binary runs as a child process. After
evidencectlisrelinked with that rpath, both targets pass (14/14 and 11/11). CI on Linux
is not affected.
registry-renderservefixture (
serve_health_and_readyin this run), before the fixtures gainedtheir retry: the child exited with status 20 because another socket took its
port between discovery and its own bind ("Address already in use"). Main's
version of the test fails the same way. The fixtures now move to a fresh
port and retry, at most three times, only for that refusal; any other early
exit fails at once with the server's output. A regression test holds the
fixture's port to prove the retry, and with it 60 direct runs of the serve
tests passed, 23 of 23 each.
bregctlexpression check: 1 passed.Casework PostgreSQL suites:
postgres_transactionscaseworkctllibbreg_review_journeyreview_httpreview_postgresBReg PostgreSQL suites (PostGIS):
registry-bregrun withpostgres-test,tooling: 2181 passed, 1failed, 15 ignored.
postgres_*and schema-fingerprint targets: 668 passed, 1 failed, 11ignored.
BREG_TEST_EVIDENCE_BINARY. Rerun with a builtevidencebinary, the wayproducts/breg/scripts/test-postgres.shprovides it, the Evidence targetspass:
postgres_action_evidence5/5,postgres_action_evidence_retention4/4,
postgres_action_evidence_targets1/1.breg-reviewpostgres_breg: 4 passed.breg-mcppostgres_gateway: 6 passed, 1 ignored.Product gates:
The dependency-direction checks run inside the checkpoints and pass.
Configuration conventions:
Generators. Every generator this branch touches was rerun with its
documented command, and
git statusstayed clean. That covers the platformshared blocks, the BReg runtime, authoring, and tool schemas, the Casework
project and runtime schemas, OpenAPI, and CLI schemas, the Scheduling
authoring and runtime schemas and OpenAPI, the Messaging runtime schema and
OpenAPI, the identifier catalog with
--check-references, and the Node.jsfacade sync. The review round reran the Scheduling runtime schema, the
Messaging OpenAPI document, and the identifier catalog.
Bindings.
check:types)Release scripts (before the review round; this head's reruns are in the
first table).
check-debian13-images.pyrehearse-upgraderegistry-release validate-currentDocs site.
node --test "scripts/**/*.test.mjs": not rerun.npm run check, including the evidence anchors, the CLI reference, and thebuilt link check: not rerun.
Issue
Refs #1952
This PR does not close #1952. It delivers the deferred grant lifecycle, its
contracts, and enforcement in each product. The issue also asks for proof that
a real wait of more than fifteen minutes, with the caller restarting, works end
to end through Casework and Scheduling. The tests here simulate elapsed time
and run Scheduling against a stub status authority. The Coordinator PR's native
journey makes that proof with a persisted wait of more than fifteen real
minutes and an actual worker restart, so that PR should close the issue.
Closes #1936: CI now runs
crates/registry-casework/tests/task_grant_invalidation.rson every Caseworkchange.