Bind the decision to one change

Record the repository reference, full revision, the supplied textual diff, and its SHA-256 digest. The local gate recomputes that digest from the declared synthetic diff; if the diff changes, it rejects the record until the review is restarted. Then declare the Kubernetes version and the smallest policy question the reviewer must answer.

Declaration It does not prove
Concurrency policy That an overlapping effect cannot happen elsewhere
Missed-run deadline or hold rule That every old occurrence was classified correctly
Unresolved idempotency boundary That retry or catch-up is safe
Hold for a named non-production fixture test That the target cluster or production effect was exercised
Local rollback route That a cluster rollback has been performed

Keeping uncertainty explicit is stronger than assuming a policy name supplies business semantics.

Run the local admission gate

The synthetic declaration below makes the local gate inspectable. Its revision and digest are fixture values, not a real repository change or cluster result:

import { createHash } from "node:crypto";

const diffText = "--- fixture-cronjob.yaml\n+++ fixture-cronjob.yaml\n@@\n-concurrencyPolicy: Allow\n+concurrencyPolicy: Forbid\n";
const policyDeclaration = {
  repositoryReference: "repo:example/scheduler",
  revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  diffText,
  diffDigest: createHash("sha256").update(diffText).digest("hex"),
  boundary: "synthetic-local-cronjob-policy",
  kubernetesVersion: "kubernetes-v1.33",
  concurrencyPolicy: "forbid",
  missedRunPolicy: "declared-deadline-or-hold",
  effectBoundary: "idempotency-unproven",
  outcomeRoute: "hold-for-non-production-cluster-test",
  clusterTestPlan: "named-non-production-cronjob-fixture",
  clusterTestFixture: "fixture:cronjob-catch-up-non-production",
  reviewer: "reviewer:platform-maintainer",
  rollbackRoute: "local-revert-and-hold"
};
// With the local gate, this fixture produces: { admitted: true }

This page includes the declaration for inspection; the repository test remains a local editorial fixture. Run it if you have the accompanying source:

node --test sites/odexing.com/evidence/P217/cronjob-catch-up-gate.test.mjs

The gate accepts a synthetic local declaration only when the immutable change identity is bound to its declared diff, a named Kubernetes version, allowed concurrency policy, declared missed-run policy, unresolved effect boundary, a hold for a named non-production fixture, reviewer identifier, and local rollback route are present. It labels a test hold without reading a manifest, connecting to a cluster, running a Job, or approving a merge. It binds the declared diff as an identity record; it does not prove that the separately declared policy fields match that diff.

Require the cluster-specific questions

Before merge, a human maintainer still needs to compare the declaration against the actual manifest and target environment. Ask whether a long-running job can overlap, what happens after suspend and resume, how an old occurrence is classified, what records make a duplicate effect detectable, and which revision returns the fixture to its prior state. Keep these questions bounded to one CronJob and a named non-production test environment.

Reject the proposal when the version is merely “current,” the effect is called safe without evidence, or a rollback is only a remembered command. The local gate is an admission record, not a substitute for a manifest review or a cluster exercise. For a neighbouring recovery boundary, see Gate an Agent-Generated Retry-Policy Change Before Merge.