What
CreateProposalDto.ProvenanceTotalTokens (backend/src/Taskdeck.Application/DTOs/AutomationProposalDtos.cs, positional int parameter) is still bindable from the POST /api/automation/proposals request body and flows into the stored ProposalProvenance row as Math.Max(0, dto.ProvenanceTotalTokens) (AutomationProposalService.cs, provenance construction). After PR #2600 (#2583) the producer identity fields (ProvenanceModelId, ProvenanceProvider, ProvenancePromptVersion) are [JsonIgnore], but an authenticated caller can still plant a fabricated token count on the same record.
Found by the fresh-context review of PR #2600 (LOW, out of that issue's scope). Refs #2583, #1987, #2499.
Why it matters
Token counts feed usage and cost views; a client-planted number is a false usage claim attributed to the server's producer triple. Low severity because it is not identity and the value is clamped at zero, but it is the same trust-boundary class the sibling fields were closed for.
Fix
- Make
ProvenanceTotalTokens a [JsonIgnore] init-only property like its three siblings; keep application-layer callers (CaptureTriageService, workers) stamping it.
- Extend
AutomationProposalsApiTests.CreateProposal_ExternalProducerTriple_IsNotBoundFromTheCreateBody (or add a sibling case) to post a provenanceTotalTokens value and assert the stored row carries 0 (or the server value), red-first.
- Backend only, no migration.
What
CreateProposalDto.ProvenanceTotalTokens(backend/src/Taskdeck.Application/DTOs/AutomationProposalDtos.cs, positionalintparameter) is still bindable from thePOST /api/automation/proposalsrequest body and flows into the storedProposalProvenancerow asMath.Max(0, dto.ProvenanceTotalTokens)(AutomationProposalService.cs, provenance construction). After PR #2600 (#2583) the producer identity fields (ProvenanceModelId,ProvenanceProvider,ProvenancePromptVersion) are[JsonIgnore], but an authenticated caller can still plant a fabricated token count on the same record.Found by the fresh-context review of PR #2600 (LOW, out of that issue's scope). Refs #2583, #1987, #2499.
Why it matters
Token counts feed usage and cost views; a client-planted number is a false usage claim attributed to the server's producer triple. Low severity because it is not identity and the value is clamped at zero, but it is the same trust-boundary class the sibling fields were closed for.
Fix
ProvenanceTotalTokensa[JsonIgnore]init-only property like its three siblings; keep application-layer callers (CaptureTriageService, workers) stamping it.AutomationProposalsApiTests.CreateProposal_ExternalProducerTriple_IsNotBoundFromTheCreateBody(or add a sibling case) to post aprovenanceTotalTokensvalue and assert the stored row carries 0 (or the server value), red-first.