Skip to content

feat(scheduling): Registry Scheduling MVP - #1092

Merged
jeremi merged 115 commits into
mainfrom
feat/scheduling-mvp
Sep 21, 2026
Merged

jeremi merged 115 commits into
mainfrom
feat/scheduling-mvp

Conversation

@jeremi

@jeremi jeremi commented Sep 15, 2026

Copy link
Copy Markdown
Member

Draft, opened to get CI running against the branch and to give the work a home for review. Not ready to merge.

Size

101 commits, 122 files, 42717 insertions, 145 deletions. 81 files added, 39 modified, one rename, one copy.

What it adds

Five new workspace crates, all wired into the root Cargo.toml at 0.32.0:

  • registry-scheduling-core, the source-neutral model, admission rules, policy, diagnostics, problem catalog, and fixtures
  • registry-scheduling, the runtime and the scheduling binary
  • registry-schedulingctl, adopter and operator tooling and the schedulingctl binary
  • registry-scheduling-client, the Rust client
  • registry-platform-calendar, shared calendar primitives

AGENTS.md is updated to describe Scheduling as a fifth independent runtime product, with the boundary stated explicitly: Scheduling owns its capacity ledger absolutely, a hold or appointment is created, moved, or released only inside the Scheduling runtime's own capacity transaction, and no other product may write to that ledger directly or through a shared database.

Commit scopes, complete: 30 fix(scheduling), 20 feat(scheduling), 11 docs(scheduling), 6 test(scheduling), 6 fix(schedulingctl), 4 docs, 3 feat(schedulingctl), 2 feat(platform), 2 chore(scheduling), 1 each of test(release), test(breg), refactor(casework), fix(scheduling-client), fix(platform), fix(platform-calendar), fix(ci), feat(scheduling-core), feat(auth), docs(site), docs(schedulingctl), ci(scheduling), ci, chore(schedulingctl), chore(identifiers), chore, test(schedulingctl).

Beyond the new crates it touches products/scheduling (29 files), docs (18), release (7), .github (4), products/identifiers (2).

Worth a reviewer's attention

Three things reach outside the Scheduling crates and are the parts most worth arguing about:

  1. crates/registry-casework-core/src/calendar.rs moves to crates/registry-platform-calendar/src/working_day.rs (85% similarity). Calendar logic is lifted out of Casework into a shared platform crate so Scheduling can use it without depending on Casework. The Casework public API is preserved by re-exporting the moved items from registry-casework-core. That is the right direction given the product boundaries, but it changes a Casework-owned file and deserves a second opinion on the seam.
  2. crates/registry-platform-oidc gains a Scheduling variant on GrantBounds plus its bounded permission type (3 files). The change is additive, but the crate is shared by every product, so it is worth checking nothing narrows or widens for the existing callers.
  3. crates/registry-breg/src/task_grant/tests.rs and crates/registry-cli-docs are each touched lightly. Scheduling verifies a task grant, so the BReg test change is expected, but it is a cross-product edit.

State

  • Rebased onto main and force-pushed. The rebase was clean: the branch and the three commits it was behind touch disjoint file sets.
  • docs/site/src/data/cli-reference.yaml carries a fresh v3 publication record for 0.32.0, reviewed against a generated catalog diff rather than stamped blind. The only catalog delta against main is the two added binaries scheduling and schedulingctl; every other command tree is byte-identical.
  • Cargo.lock gains only the five new workspace crates. No third-party version moved and nothing was removed, so every other product builds against an identical dependency graph.

What the first CI run found

One real defect, now fixed on the branch: intents_postgres seeded its base time straight from the clock and compared the value PostgreSQL returned against the nanosecond-precision value still held in memory. timestamptz resolves to microseconds, so the tail was dropped on write. This failed on every Linux run and passed on every macOS one, because the two platforms' realtime clocks differ in resolution, which is why it reached CI at all. The fix truncates the seeded instant to microseconds.

One unrelated gate flaked: Base Registry Engine product contracts (postgres) refused a caseworkctl dev session with a generic runtime_dependency diagnostic, then passed on a re-run of the same commit. That test starts a dev session with a stock issuer, a database, and four ports, so it is load sensitive. Not caused by this branch: the branch touches neither the Casework runtime, nor caseworkctl, nor that test, nor that job.

@jeremi
jeremi force-pushed the feat/scheduling-mvp branch 2 times, most recently from 7ed0254 to 7be7edc Compare September 17, 2026 13:14
@jeremi
jeremi marked this pull request as ready for review September 19, 2026 19:25
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 19, 2026

Copy link
Copy Markdown

Codex Review Summary

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

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-21T11:52:01.116292Z e807da4 New commits
ℹ️ 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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9674e86e93

ℹ️ 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".

Comment thread crates/registry-scheduling/src/store.rs Outdated
Comment thread crates/registry-scheduling/src/service.rs
Comment thread crates/registry-scheduling/src/runtime.rs
Comment thread crates/registry-scheduling-core/src/model.rs
Comment thread crates/registry-scheduling-core/src/admission.rs
Comment thread crates/registry-scheduling/src/store.rs
Comment thread crates/registry-scheduling/src/store.rs
Comment thread crates/registry-scheduling/src/store.rs
@jeremi
jeremi force-pushed the feat/scheduling-mvp branch from 4bf86bc to 34deb3e Compare September 20, 2026 01:57

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e590e5cc66

ℹ️ 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".

Comment thread crates/registry-scheduling/src/service.rs
Comment thread crates/registry-scheduling/src/store.rs Outdated
Comment thread crates/registry-scheduling/src/service.rs Outdated
Comment thread crates/registry-scheduling/src/service.rs Outdated
Comment thread crates/registry-scheduling/src/service.rs Outdated
Comment thread crates/registry-schedulingctl/src/records.rs
Comment thread crates/registry-scheduling-core/src/resolve.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8491a37f4a

ℹ️ 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".

Comment thread crates/registry-scheduling/src/store.rs
Comment thread crates/registry-schedulingctl/src/records.rs Outdated
Comment thread crates/registry-scheduling-client/src/client.rs Outdated
Comment thread crates/registry-scheduling-core/src/admission.rs
Comment thread crates/registry-scheduling-core/src/admission.rs
Comment thread crates/registry-scheduling/src/service.rs Outdated
Comment thread crates/registry-scheduling/src/service.rs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 68e3060fbd

ℹ️ 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".

Comment thread crates/registry-scheduling/src/runtime.rs
Comment thread crates/registry-scheduling/src/store.rs
Comment thread crates/registry-scheduling-core/src/policy.rs
Comment thread crates/registry-scheduling-core/src/policy.rs Outdated
Comment thread crates/registry-scheduling-core/src/policy.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0aecb1a8e5

ℹ️ 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".

Comment thread crates/registry-scheduling/src/store.rs
Comment thread crates/registry-scheduling/src/store.rs
Comment thread crates/registry-scheduling/src/store.rs
Comment thread crates/registry-scheduling-core/src/admission.rs
Comment thread crates/registry-scheduling/src/store.rs
Comment thread crates/registry-scheduling/src/service.rs
Comment thread crates/registry-scheduling/src/store.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 046e23ce6d

ℹ️ 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".

Comment thread README.md Outdated
Comment thread crates/registry-stack-client/src/lib.rs Outdated
Comment thread crates/registry-scheduling/src/store.rs
Comment thread crates/registry-scheduling/src/service.rs Outdated
Casework clocks and Scheduling openings evaluate the same mathematical
object: working days, holiday revisions, and timezone-correct local
instants. Move the evaluator into a new registry-platform-calendar crate
so both products share one implementation, and add the weekly-opening
expansion Scheduling needs: bounded patterns become concrete half-open
UTC intervals, daylight-saving gaps and folds are explicit errors rather
than silent shifts, and exception layering makes a blocking closure win
over an opening while an authorized reopening adds time back only inside
the closure it names.

registry-casework-core re-exports the platform crate through its flat
glob, so its public surface is unchanged. CalendarEvaluationError keeps
every original variant verbatim and gains the weekly diagnostics; it
loses Copy because the new variants carry identifiers.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
GrantBounds gains a closed `scheduling` tag whose permissions bind one
service and location pair to a bounded action vocabulary, mirroring the
existing BREG bounds shape. Existing evidence and breg accessors return
None for it, and a scheduling_permissions accessor joins them.

Validation:
- Threat: grant bounds carry the cross-product authorization payload
  inside a signed task grant, so a new variant is where semantics could
  leak from one product's runtime into another's. The variant stays a
  closed union member: a verifier that does not know the tag rejects it
  as a malformed bound at authentication and never interprets it, and
  the Evidence and BREG consumers read bounds only through their
  accessors, which return None for scheduling grants.
- Wire format: inside the signed registry_grant_bounds claim,
  {"type":"scheduling","permissions":[{"service":...,"location":...,
  "actions":[...]}]}. No existing claim changes shape; the union gains a
  tag and nothing else.
- Compatibility: issuers on older code cannot mint the tag and verifiers
  on older code refuse it as malformed, which is the intended fail-closed
  behavior; no token signed before this change carries scheduling bounds.
- Limits: 64 permissions of 32 actions, service and location values
  <=512 bytes with no whitespace or wildcard, actions in the existing
  lowercase operation grammar, (service, location) pairs unique; Debug
  redacts service, location, and action values.
- Tests: registry-platform-oidc 81 passed (variant distinctness,
  cardinality at and over the limits, wildcard, whitespace, and duplicate
  refusal, scheduling Debug redaction); cargo fmt/check/clippy
  --workspace --all-targets -D warnings clean; cargo test --workspace
  green with BREG_TEST_DATABASE_URL set on a disposable PostGIS instance
  (registry-breg: 53 suites, 373 passed, 0 failed; the casework clock
  PostgreSQL journey also passes against the extracted calendar);
  cargo deny check ok for advisories, bans, licenses, and sources.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
A reopening restored the closure it named even when that closure reached
outside the pattern's own time, so an operator could extend published
hours through the exception layer rather than through the reviewed
pattern. A reopening now restores only pattern time its closure removed:
it must sit inside the pattern's hours on its date, on a pattern weekday,
inside the effective range, and on a non-holiday date, or the evaluation
refuses with the reopening's identifier.

Dated local intervals gain their own conversion with dedicated error
variants: local_interval turns one wall-clock interval on a date into a
half-open UTC interval in a named timezone, refusing gap and fold
instants explicitly, and InvalidIntervalDate and InvalidIntervalTimes
replace the exception-scoped variants a placeholder id used to force.

Review notes: the reopening tightening changes what an authorized
exception may publish, so the tests pin every refused shape (outside
pattern hours, reaching past pattern end, holiday date, non-pattern
weekday, out of effective range) beside the restored ones (identity
reopening of a whole closure, adjacency to an unrelated closure), plus
the fold-spanning interval that keeps real elapsed time.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
GrantBounds::Scheduling shipped with SchedulingPermission private to the
crate, so no relying product could name the permission it verifies.
Export it through the crate root and pin the wire form: the scheduling
tag round-trips through serde, refuses unknown members at the union and
the permission-value level alike, and enforces its value boundaries.

The review record for the scheduling bounds moves from the M0b commit
message into the crate README, where the BREG and Evidence bounds
records already live, so a reviewer of a later change finds the limits
and redaction decisions beside the code.

Review notes: authorization-relevant but behavior-neutral on the wire.
No claim shape changes and no verifier changes; the export makes an
existing closed type nameable, and the round-trip test holds the tag
spelling so a write-side regression fails before validation runs.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
The scheduling bounds are a closed union member the BREG binding must
never interpret: a task grant carrying them is refused as a malformed
bound at authentication, the same fail-closed path as every bound the
verifier does not know. Pin that refusal so a future accessor addition
cannot silently admit scheduling grants to BREG actions.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Registry Scheduling Milestone 1, the offline checkpoint: everything that
decides an admission and everything that proves it, with no runtime yet.

registry-scheduling-core holds the source-neutral model and the pure
evaluators. The authored policy declares services, offerings, opening
patterns, holiday sets, published windows, and the hold policy; the
environment facts (locations, pools, dated exceptions) stay runtime
records the policy references but never embeds, so one published policy
governs every environment that resolves its identifiers. The evaluators
are total functions of resolved policy, facts, ledger snapshot, request,
and observed instant: no clock, no socket, no database. The runtime will
call them inside its capacity transaction, the explain endpoint will
call them again for an authorized caller, and fixture replay calls them
with synthetic facts, so the three cannot disagree about what admits.

Every refusal carries two problem codes from the closed 26-code
vocabulary: the public one every caller may see and the detailed one
only the authorized explain path may see. Exactly one code,
resource.unavailable, is detailed-only, because a specific resource's
absence can disclose another person's booking or a private staff
reason. authorization.refused is an audit reason, never a problem code.
Interval arithmetic that leaves representable time refuses as a horizon
answer, never a mislabeled capacity refusal and never a clamped buffer
that undercounts occupancy; window allocation saturates instead of
wrapping past u32.

Fixtures replay offline: synthetic facts, a starting ledger, ordered
cases with expected outcomes. Replay runs the same evaluators, records
admitted cases into the ledger later cases contend against, and refuses
a fixture naming a code outside the vocabulary or a detailed-only code
before any case runs. Structural accesses are total: a policy whose
check did not pass fails the fixture with a typed error naming the case,
never a panic.

schedulingctl authors and proves: init writes a complete starter project
from one of two templates, check validates offline, test replays every
fixture, explain publishes what the runtime would serve. check exits
zero with findings by default and gains --deny-findings for CI, matching
caseworkctl; a fixture run with failing cases always exits nonzero.
Reports render in text or JSON with path-addressed diagnostics.

products/scheduling carries the dependency-direction gate holding the
boundary: the core never references runtime, protocol, or storage types,
and no product term leaks into a platform crate.

Tests: registry-scheduling-core 71 passed, registry-schedulingctl 22
passed, the template projects init/check/test/explain green end to end;
cargo fmt, check, and clippy -D warnings clean across the workspace;
cargo test --workspace green with the disposable PostGIS databases set;
cargo deny check ok; the scheduling dependency-direction gate passes.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
INT-02 makes reminders configurable at the service-design layer and binds
each intent to an appointment revision, and AT-08 asserts a reschedule
leaves no active reminder for the old revision. Both need an authored
reminder schedule to exist, or the invariant is only vacuously true, so the
policy gains one reminder offset type on each offering: minutes_before and
a review because, validated like every other authored choice (zero,
duplicate distances, and blank reasons are findings). Message transport
stays external: the runtime mints revision-bound intents from these
offsets, and an adopter with no consumer reads them back.

The standalone-exact-time template authors two offsets on the counter
offering so the runtime demo can show a real intent being suppressed.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
The HTTP documents both the runtime and every client speak: the catalogue
(service, offering, window, reminder), availability entries as a kind-tagged
union of grid slots and windows, pages with cursors, holds, appointments and
their requests, history entries, and the explain document with its public and
detailed problem codes side by side.

They live in the source-neutral core beside the model they project, the way
the Casework DTOs live in registry-casework-core, so the client crate depends
on core and never on the runtime. Every document is camelCase and refuses
unknown fields. The projections are deliberate: because reasons never
publish, callers see displayed times rather than occupied intervals, and the
detailed code that names unavailability appears only on the separately
authorized explain path.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Every code in the closed vocabulary now carries its HTTP status, title, and
value-free remediation detail beside the code string itself, so the runtime
emits and every client validates one pinned mapping rather than each
re-deriving its own. The map is part of the wire contract: a caller can
enumerate every problem this product can return and know the status it
arrives with.

Statuses follow the acceptance reasoning: recoverable conflicts answer 409,
holds and idempotency receipts that no longer exist answer 410, stale
revisions answer 412, a missing precondition answer 428, requests the
published policy could never serve answer 422, and checks that could not run
answer 503. Transport statuses (404, 405, 413, 415) are deliberately absent:
edge rejections belong to the platform's own problem namespace, never to the
domain vocabulary.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
The route paths, the idempotency-key header, the cursor and limit query
parameters, and the idempotency key bound are contract the runtime and every
client share, so they live in core beside the artifact names and are pinned
by the same style of test. The resource and location listings gain their
documents: a resource is a concrete pool member, never an independent
counter, and a location carries the IANA timezone its openings expand in.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
The relying-party client for Registry Scheduling: fourteen methods over
the pinned exact-time HTTP contract, each taking a borrowed bearer token
by value and answering one completed call with the response document and
its validated trace identifier.

Every failure lands in one of four matchable shapes: a caller-side
configuration or request defect validated before any network input or
output, a transport failure, a protocol failure naming the stage where
the wire stopped matching the pinned contract, and an exactly validated
product problem surfaced as the core's closed ProblemCode. A problem
document only becomes a domain problem when its status, type URI, title,
detail, code, and trace identifier all equal the pinned definition; any
mismatch, and any platform-owned transport problem, is edge talk.

Mutating calls carry a caller-supplied idempotency key validated against
the pinned bound. Route identifiers are validated as one path segment
before interpolation, so an opaque id can never silently detour to a
different route. Bodies are read under a bounded byte ceiling and the
core documents refuse unknown fields, so a response is exactly the
contract or a protocol failure. The client never retains a token, never
follows a redirect, and never retries a mutation.

Boundary: the client depends on registry-scheduling-core and the shared
registry-platform-httpsec and registry-platform-httputil primitives
only, never on the Scheduling runtime or its operator tooling, and adds
no scheduling semantics of its own.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
The service owns the three decisions the store cannot. Authorization:
every mutating call must carry a task grant whose scheduling permissions
name the offering's service, location, and the operation, and the store
re-checks the grant's expiry inside the capacity transaction. Disclosure:
every refusal projects to its public problem code, and only the
separately authorized explain path sees the detailed one; an admitted
start carries no codes at all, because there is no refusal to explain.
Attributability: the commitment's audit record carries pseudonymized
principal, client, grant, and approver references, and a refused
commitment records its receipt under the caller's idempotency key so a
replay answers exactly as the first attempt did.

Availability is bounded: exact-time offerings walk their authored grid
inside the published openings, clear of closures, past lead time, inside
the horizon, and only list a slot at least one available member can
still serve; arrival windows list their remaining units. A stored
success receipt carries the minted claim itself, so a replayed response
is the original response through the same projection, not a
re-derivation from live state.

The policy-to-context resolution moves from the replay fixtures into the
core beside the evaluators, so the offline replay and the live runtime
expand the same openings and closures and cannot disagree about what a
location published.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
records apply performs the one attributable operator write of a
deployment's live environment records: the document is parsed and
validated offline in its own terms (duplicates, timezone, undeclared
exception locations, strict dates and times) before any connection
opens, then lands through the store's single replace transaction with
its operator audit row. A PostgreSQL integration test behind the
postgres-test feature proves the wholesale swap and both audit rows
on a disposable schema.

package writes the deployment identity the runtime verifies: the
manifest lands beside the authored policy, an existing manifest is
refused rather than replaced, and the written manifest is proven to
verify through the runtime's own verifier before success is reported.

Runtime-configuration and store failures now map to their own
diagnostics instead of the generic authoring refusal, and the store
binds exception dates as text cast to date, the pattern the rest of
the workspace uses for typed columns.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
The request-edge rejections (400/404/405/413/415/422) join the closed
problem vocabulary under the product's own prefix, exactly as Casework
carries them: no shared platform problem prefix exists in the Registry
Stack identifier catalog. The client now types the product's own
request-edge documents and treats only foreign dialects as edge talk.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
jeremi and others added 13 commits September 21, 2026 15:55
The database-test isolation gate now reports a maintained database suite
whose required-features gate disappeared, and a dependency entry that
asks for a feature whose expansion enables a sibling's gate, not only
the gate's own name. The known suites are named so losing a gate fails
the checkpoint rather than passing silently.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
The contracts validator now asks each cited test's own runner for its
inventory instead of matching names in source text: cargo lists the
selected target's tests under the citation's features, unittest
discovers the Python module, and neither executes a test body. The one
citation living behind a feature gate names the feature in the matrix
and the traceability file. The database-suite gate reads Cargo's
resolved default features, so aliasing or forwarding postgres-test into
a default build fails the checkpoint, and an ordinary ungated
integration test is no longer mistaken for a database suite.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
SCHEDULING-SEC-14 is recorded as enforced and promises an authorization
audit record for every refusal the ledger decides. The guard selecting
which outcomes to record matched only an admission refusal, the hold
ceiling, and a lapsed grant, so a stale observed revision and a
cancellation past its cutoff were answered as refusals with nothing
written behind them. Both are decisions about a named appointment under
a grant the service had already matched, which is exactly what the
invariant exists to attribute.

Replace the wildcard match with an exhaustive one, so a new CommitError
variant has to state whether it is a decision or a fault instead of
inheriting silence. Faults decide nothing and stay unaudited; an
idempotency key refusal stays unaudited because the attempt receipt
already carries it and the key says nothing about what a grant reaches.

Narrow the invariant's enforcement point to name the outcomes on each
side, so the contract asserts what the code performs rather than a
looser claim it did not meet.

Security review notes: this changes audit integrity. It only adds
records; no existing record changes shape, reason, or ordering, and the
hash chain is untouched. The added records carry the same pseudonymized
principal and grant as the refusals already audited beside them, so no
caller identifier reaches the journal in the clear. The new test asserts
both the added rows and the absence of the raw principal.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
The install block advertised scheduling-install.sh and a
SCHEDULING_INSTALL_DIR override, but the release candidate's payload
inventory carries no scheduling binary and no scheduling installer, and
that inventory is checked for exact equality. Both links would answer
404 on the next release, and adding the assets to a manifest without
first extending the inventory would be refused as unexpected payloads.

Say what is true today: Scheduling publishes a container image, which
the release model does carry, and has no released binary or installer
yet. Wiring the binaries and the installer into the release pipeline
touches release provenance and belongs in its own reviewed change.

Move the CLI publication review date to the day the combined command
content was last reviewed against this branch.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 84c301bbbc

ℹ️ 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".

Comment thread crates/registry-scheduling/src/runtime.rs
Comment thread crates/registry-scheduling/src/service.rs
…variants

The canonical validation of a policy against the published window records
it governs runs only in the authoring tooling. Neither database write
repeats it: policy publication fences offerings carrying active claims but
never reads the window records, and records replacement never reads the
deployed policy. An operator bypassing the authoring tooling can back an
exact-time offering with a pool that already staffs a published window, and
the two modes then draw the same staffing through separate anchor rows.

No matrix row claimed this was enforced, so the security contract was
accurate but silent. Record it as SCHEDULING-DEF-07 with the authoring
refusal as its compensating control, restate it in the review notes the
row points at, and name the limit in the changelog beside the ledger
promise it qualifies.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e807da43f8

ℹ️ 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".

Comment thread crates/registry-scheduling/src/store.rs
Comment thread crates/registry-scheduling/src/store.rs
Comment thread crates/registry-scheduling-core/src/policy.rs
Comment thread crates/registry-scheduling-client/src/client.rs
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.

1 participant