Skip to content

feat(requests): let RuleDocumentation express an object property allowlist (additionalProperties/propertyNames) #548

Description

@Radiergummi

Summary

RuleDocumentation cannot express an object property allowlist — a fixed set of permitted keys with additionalProperties: false. A SelfDocumentingRule for a rule that constrains an object's shape (allowed keys, an enum of keys) can therefore only degrade to a description-only type: object.

Motivation (dogfooding: a private consumer app)

Implementing SelfDocumentingRule on the app's custom rules (rule.unknown 128 → 9) surfaced this. App\Rules\KeysIn (used 26 times) validates that an object contains only a fixed set of keys:

readonly class KeysIn implements ValidationRule
{
    public function __construct(protected array $values, ...) {}
    // passes when array_diff_key($value, array_flip($this->values)) === []
}

The faithful schema is { type: object, additionalProperties: false, properties: { <key>: {}, … } } (or at least the allowed key set), but RuleDocumentation has no field for it, so the best achievable is:

new RuleDocumentation(
    description: 'An object limited to these keys: a, b, c.',
    type: 'object',
);

The constraint survives only as prose.

Proposed enhancement

Add optional fields to RuleDocumentation for object-shape constraints, applied by the same "write only when the descriptor has no value yet" merge policy as the existing fields:

  • additionalProperties: bool|null (emit additionalProperties: false).
  • propertyNames: list<string>|null — the allowed key set. Either materialise properties: { key: {} } for each, or emit a JSON-Schema propertyNames: { enum: [...] }.

(Naming/shape open to design — the point is a first-class way to express "these keys, nothing else".)

Scope

Small, additive VO change plus the write path in ValidationRulesToSchema (or wherever RuleDocumentation is applied to a field descriptor). No behavioural change for rules that don't set the new fields.

Notes

Found while implementing SelfDocumentingRule across 8 real custom rules; KeysIn was the only one the VO could not represent faithfully.

Metadata

Metadata

Assignees

Labels

area:requestsRequest-body inferencespecCarries an implementation spec (planning issue)

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions