⚠️ Definition of Done: this issue must be completed in full, in a single PR. Do not split this
work across multiple PRs, and do not defer any Deliverable below to a follow-up issue. A PR that
satisfies only some of the Deliverables, stubs a required test, or leaves a checkbox
partially-done does NOT resolve this issue and will be closed.
Context
src/scenarios/input-model.ts:189-220's exported assertScenarioLocalBranchInputSafe is framed (by its own comments and the recent #8328 fix, which added the "reject non-array changedFiles" branch) as the guard preventing source-content upload in scenario inputs -- it scans for FORBIDDEN_SOURCE_UPLOAD_KEYS (sourceContent, diff, patch, etc.) and oversized changedFiles entries. Grep across src/, packages/, and scripts/ shows zero production importers -- only its own unit test (test/unit/scenario-input-model.test.ts) calls it. The real production caller, packages/loopover-mcp/lib/local-branch.ts:125, calls a different, weaker local function assertSourceUploadDisabled() (lines 707-711) that only checks the LOOPOVER_UPLOAD_SOURCE env flag -- it does not scan for forbidden keys or oversized content at all, even though CollectLocalBranchMetadataInput (same file, lines 44-56) passes several unknown-typed fields (scenarioNotes, validation, projectedCredibility, branchEligibility, labels) straight through to the output payload.
Requirements
Wire assertScenarioLocalBranchInputSafe into the real local-branch collection path in packages/loopover-mcp/lib/local-branch.ts (either as a replacement for, or in addition to, assertSourceUploadDisabled), so the forbidden-key/oversized-content scan actually runs on the production entry point. Do not simply delete the function -- its scanning logic is the documented safety mechanism and has no replacement; wiring it in is the correct fix.
Deliverables
All of the above Deliverables are required in the same PR unless the deliverable text itself states otherwise.
Test Coverage Requirements
src/** -- 99%+ patch coverage, branch-counted, on the new wiring and its rejection path.
Expected Outcome
The production local-branch scenario-collection path actually enforces the forbidden-source-upload-key and oversized-content scan, closing a dead-security-guard gap.
Links & Resources
src/scenarios/input-model.ts:189-220
packages/loopover-mcp/lib/local-branch.ts:44-56,125,707-711
test/unit/scenario-input-model.test.ts
Context
src/scenarios/input-model.ts:189-220's exportedassertScenarioLocalBranchInputSafeis framed (by its own comments and the recent #8328 fix, which added the "reject non-arraychangedFiles" branch) as the guard preventing source-content upload in scenario inputs -- it scans forFORBIDDEN_SOURCE_UPLOAD_KEYS(sourceContent,diff,patch, etc.) and oversizedchangedFilesentries. Grep acrosssrc/,packages/, andscripts/shows zero production importers -- only its own unit test (test/unit/scenario-input-model.test.ts) calls it. The real production caller,packages/loopover-mcp/lib/local-branch.ts:125, calls a different, weaker local functionassertSourceUploadDisabled()(lines 707-711) that only checks theLOOPOVER_UPLOAD_SOURCEenv flag -- it does not scan for forbidden keys or oversized content at all, even thoughCollectLocalBranchMetadataInput(same file, lines 44-56) passes severalunknown-typed fields (scenarioNotes,validation,projectedCredibility,branchEligibility,labels) straight through to the output payload.Requirements
Wire
assertScenarioLocalBranchInputSafeinto the real local-branch collection path inpackages/loopover-mcp/lib/local-branch.ts(either as a replacement for, or in addition to,assertSourceUploadDisabled), so the forbidden-key/oversized-content scan actually runs on the production entry point. Do not simply delete the function -- its scanning logic is the documented safety mechanism and has no replacement; wiring it in is the correct fix.Deliverables
packages/loopover-mcp/lib/local-branch.ts's production local-branch collection path callsassertScenarioLocalBranchInputSafe(in addition to or in place ofassertSourceUploadDisabled)local-branch.ts) rejects a forbidden-key/oversized payload, not just the unit-levelassertScenarioLocalBranchInputSafetestAll of the above Deliverables are required in the same PR unless the deliverable text itself states otherwise.
Test Coverage Requirements
src/**-- 99%+ patch coverage, branch-counted, on the new wiring and its rejection path.Expected Outcome
The production local-branch scenario-collection path actually enforces the forbidden-source-upload-key and oversized-content scan, closing a dead-security-guard gap.
Links & Resources
src/scenarios/input-model.ts:189-220packages/loopover-mcp/lib/local-branch.ts:44-56,125,707-711test/unit/scenario-input-model.test.ts