Found while triaging #16 during the 2026-08-27 queue drain. Filing rather than fixing, because the fix is a design decision and the authoring context (Codex) is stopped.
The defect
On codex/public-trust-v2, production-lifecycle-policy.json and schemas/production-lifecycle-policy.schema.json were migrated to v2 keys. scripts/validate_production_lifecycle.py was not. The data and the schema agree with each other; the imperative validator is the straggler, and check_profile.py imports it and surfaces the error.
Evidence
_validate_policy at line 343 passes a closed key set that still names the v1 keys:
"maximum_admission_days",
"summary_authority",
The v2 policy's actual top-level keys are:
$schema, schema_version, revision,
maximum_release_admission_days, maximum_workflow_admission_days,
object_reference_schema_version, release_admission_schema_version,
workflow_admission_schema_version, lifecycle_checkpoint_schema_version,
lifecycle_feed_schema_version, lifecycle_feed_ref, targets
Neither maximum_admission_days nor summary_authority appears anywhere in the v2 policy. Because the set is closed, it fails in both directions: unknown keys present, required keys absent.
Line 39 is a second straggler: POLICY_SCHEMA = "openadapt.production-lifecycle-policy/v1".
Why this is not a rename
summary_authority is not merely renamed, it is gone. Its 12-key authority block is consumed again at lines 1536, 1548 and 1601, where it drives the certificate identity check and the admission expiry window. maximum_admission_days also feeds the expiry at 1548, and v2 splits that one value into maximum_release_admission_days and maximum_workflow_admission_days.
So three questions need an answer from someone who knows the v2 intent:
- Where does summary authority come from in v2? The new
lifecycle_feed_ref and the five schema-version keys suggest it moved into the feed, but that is inference, not knowledge.
- Which of the two v2 maximums governs the expiry computed at line 1548?
- Does the 1-to-30 day bound still apply to both?
Editing only the key set would produce a validator that passes and verifies nothing, which is worse than the current loud failure.
Impact
One failing check on #16. The other two pass. #16 is parked with its cluster and is not blocked on anything else.
Added after a second review — the naive fix is worse than the bug
Two independent v1 anchors must move together, or a fix passes review and still fails:
- line 39:
POLICY_SCHEMA = "openadapt.production-lifecycle-policy/v1", while the data says /v2
- line 351: the closed key set
Correcting only the key set still fails at the schema_version check. Correcting only line 39 still fails on the closed set.
More seriously, summary_authority is not inert configuration. Deleting it without a replacement does not merely weaken the validator, it removes the certificate-identity binding while the validator continues to report success. Verified call sites, all confirmed by reading the file at codex/public-trust-v2:
| line |
what the authority block drives |
| 398 |
certificate_identity equality check |
| 618 |
release identity schema version |
| 620 |
production channel |
| 929 |
certificate identity, second call site |
| 931 |
OIDC issuer |
| 974 |
source_ref in the provenance URI |
| 1022 |
evidence manifest schema version |
| 1536, 1601 |
the block is re-read |
maximum_admission_days at line 1548 computes the admission expiry window. v2 splits it into maximum_release_admission_days and maximum_workflow_admission_days, so deciding which governs which admission kind is a second design call.
Do not fix this by editing the key set. The result would be a validator that passes CI, reports success, and no longer verifies certificate identity at all.
Found while triaging #16 during the 2026-08-27 queue drain. Filing rather than fixing, because the fix is a design decision and the authoring context (Codex) is stopped.
The defect
On
codex/public-trust-v2,production-lifecycle-policy.jsonandschemas/production-lifecycle-policy.schema.jsonwere migrated to v2 keys.scripts/validate_production_lifecycle.pywas not. The data and the schema agree with each other; the imperative validator is the straggler, andcheck_profile.pyimports it and surfaces the error.Evidence
_validate_policyat line 343 passes a closed key set that still names the v1 keys:The v2 policy's actual top-level keys are:
Neither
maximum_admission_daysnorsummary_authorityappears anywhere in the v2 policy. Because the set is closed, it fails in both directions: unknown keys present, required keys absent.Line 39 is a second straggler:
POLICY_SCHEMA = "openadapt.production-lifecycle-policy/v1".Why this is not a rename
summary_authorityis not merely renamed, it is gone. Its 12-key authority block is consumed again at lines 1536, 1548 and 1601, where it drives the certificate identity check and the admission expiry window.maximum_admission_daysalso feeds the expiry at 1548, and v2 splits that one value intomaximum_release_admission_daysandmaximum_workflow_admission_days.So three questions need an answer from someone who knows the v2 intent:
lifecycle_feed_refand the five schema-version keys suggest it moved into the feed, but that is inference, not knowledge.Editing only the key set would produce a validator that passes and verifies nothing, which is worse than the current loud failure.
Impact
One failing check on #16. The other two pass. #16 is parked with its cluster and is not blocked on anything else.
Added after a second review — the naive fix is worse than the bug
Two independent v1 anchors must move together, or a fix passes review and still fails:
POLICY_SCHEMA = "openadapt.production-lifecycle-policy/v1", while the data says/v2Correcting only the key set still fails at the
schema_versioncheck. Correcting only line 39 still fails on the closed set.More seriously,
summary_authorityis not inert configuration. Deleting it without a replacement does not merely weaken the validator, it removes the certificate-identity binding while the validator continues to report success. Verified call sites, all confirmed by reading the file atcodex/public-trust-v2:certificate_identityequality checksource_refin the provenance URImaximum_admission_daysat line 1548 computes the admission expiry window. v2 splits it intomaximum_release_admission_daysandmaximum_workflow_admission_days, so deciding which governs which admission kind is a second design call.Do not fix this by editing the key set. The result would be a validator that passes CI, reports success, and no longer verifies certificate identity at all.